diff --git a/.idea/dictionaries/Stardust.xml b/.idea/dictionaries/Stardust.xml
index 49fb13b70..56bd14789 100644
--- a/.idea/dictionaries/Stardust.xml
+++ b/.idea/dictionaries/Stardust.xml
@@ -11,6 +11,7 @@
loopers
opencv
prefill
+ recents
scriptable
storages
tasker
diff --git a/app/release/output.json b/app/release/output.json
index 2bcc50bc3..605644dc0 100644
--- a/app/release/output.json
+++ b/app/release/output.json
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":203},"path":"inrt-release.apk","properties":{"packageId":"com.stardust.auojs.inrt","split":"","minSdkVersion":"17"}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":253,"versionName":"4.1.0 Alpha3","enabled":true,"outputFile":"inrt-release.apk","fullName":"release","baseName":"release"},"path":"inrt-release.apk","properties":{}}]
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 447695b04..76c542cac 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,7 @@
-
+
@@ -15,7 +15,7 @@
-
+
@@ -85,6 +85,7 @@
android:name=".ui.edit.EditActivity_"
android:configChanges="orientation|screenSize"
android:multiprocess="true"
+ android:taskAffinity="org.autojs.autojs.edit"
android:theme="@style/EditorTheme">
@@ -275,6 +276,7 @@
+
= Build.VERSION_CODES.LOLLIPOP) {
+ finishAndRemoveTask();
+ } else {
+ finish();
+ }
}
private void showExitConfirmDialog() {
@@ -207,9 +218,9 @@ private void showExitConfirmDialog() {
.neutralText(R.string.text_exit_directly)
.onNegative((dialog, which) -> {
mEditorView.saveFile();
- EditActivity.super.finish();
+ finishAndRemoveFromRecents();
})
- .onNeutral((dialog, which) -> EditActivity.super.finish())
+ .onNeutral((dialog, which) -> finishAndRemoveFromRecents())
.show();
}
@@ -294,4 +305,5 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mRequestPermissionCallbacks.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
+
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java
index 9ef8ae67e..e4155f852 100644
--- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java
+++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java
@@ -557,7 +557,7 @@ void run() {
@OnClick(R.id.edit)
void edit() {
- Scripts.INSTANCE.edit(new ScriptFile(mExplorerItem.getPath()));
+ Scripts.INSTANCE.edit(getContext(), new ScriptFile(mExplorerItem.getPath()));
notifyOperated();
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java b/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java
index 032e40c4e..a2a96a501 100644
--- a/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java
+++ b/app/src/main/java/org/autojs/autojs/ui/main/community/CommunityWebView.java
@@ -75,7 +75,7 @@ void save() {
.subscribe(file ->
Snackbar.make(CommunityWebView.this, getResources().getString(R.string.format_file_downloaded, file.getPath())
, Snackbar.LENGTH_LONG)
- .setAction(R.string.text_open, v -> Scripts.INSTANCE.edit(file))
+ .setAction(R.string.text_open, v -> Scripts.INSTANCE.edit(getContext(), file))
.show(),
error -> {
error.printStackTrace();
diff --git a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java
index bc6cb7855..3ec2a9dc2 100644
--- a/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java
+++ b/app/src/main/java/org/autojs/autojs/ui/main/scripts/MyScriptListFragment.java
@@ -62,7 +62,7 @@ void setUpViews() {
mExplorerView.setExplorer(Explorers.workspace(), ExplorerDirPage.createRoot(Pref.getScriptDirPath()));
mExplorerView.setOnItemClickListener((view, item) -> {
if (item.isEditable()) {
- Scripts.INSTANCE.edit(item.toScriptFile());
+ Scripts.INSTANCE.edit(getActivity(), item.toScriptFile());
} else {
IntentUtil.viewFile(GlobalAppContext.get(), item.getPath(), AppFileProvider.AUTHORITY);
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java
index 78dbaccd3..3df3e7019 100644
--- a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java
+++ b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java
@@ -9,8 +9,6 @@
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -18,18 +16,18 @@
import android.view.ViewGroup;
import android.widget.ImageView;
-import org.autojs.autojs.R;
-import org.autojs.autojs.tool.BitmapTool;
-import org.autojs.autojs.ui.BaseActivity;
-
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById;
+import org.autojs.autojs.R;
+import org.autojs.autojs.tool.BitmapTool;
+import org.autojs.autojs.ui.BaseActivity;
import org.autojs.autojs.workground.WrapContentGridLayoutManger;
import java.util.ArrayList;
import java.util.List;
+import androidx.recyclerview.widget.RecyclerView;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
@@ -93,7 +91,7 @@ public boolean onCreateOptionsMenu(Menu menu) {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT)
- .setType("image/*"), 11209);
+ .setType("image/*"), 11234);
return true;
}
diff --git a/autojs/src/main/assets/modules/__dialogs__.js b/autojs/src/main/assets/modules/__dialogs__.js
index 26e782540..8217d0c0f 100644
--- a/autojs/src/main/assets/modules/__dialogs__.js
+++ b/autojs/src/main/assets/modules/__dialogs__.js
@@ -155,7 +155,7 @@ module.exports = function(__runtime__, scope){
builder.input(wrapNonNullString(properties.inputHint), wrapNonNullString(properties.inputPrefill),
function(dialog, input){
input = input.toString();
- builder.emit("input_change", dialog, input);
+ builder.dialog.emit("input_change", builder.dialog, input);
})
.alwaysCallInputCallback();
}
@@ -163,23 +163,23 @@ module.exports = function(__runtime__, scope){
var itemsSelectMode = properties.itemsSelectMode;
if(itemsSelectMode == undefined || itemsSelectMode == 'select'){
builder.itemsCallback(function(dialog, view, position, text){
- dialog.emit("item_select", position, text.toString(), dialog);
+ builder.dialog.emit("item_select", position, text.toString(), builder.dialog);
});
}else if(itemsSelectMode == 'single'){
builder.itemsCallbackSingleChoice(properties.itemsSelectedIndex == undefined ? -1 : properties.itemsSelectedIndex,
function(dialog, view, which, text){
- dialog.emit("single_choice", which, text.toString(), dialog);
+ builder.dialog.emit("single_choice", which, text.toString(), builder.dialog);
return true;
});
}else if(itemsSelectMode == 'multi'){
builder.itemsCallbackMultiChoice(properties.itemsSelectedIndex == undefined ? null : properties.itemsSelectedIndex,
function(dialog, view, indices, texts){
- dialog.emit("multi_choice", toJsArray(indices, (l, i)=> parseInt(l.get(i)),
- toJsArray(texts, (l, i)=> l.get(i).toString())), dialog);
+ builder.dialog.emit("multi_choice", toJsArray(indices, (l, i)=> parseInt(l.get(i)),
+ toJsArray(texts, (l, i)=> l.get(i).toString())), builder.dialog);
return true;
});
}else{
- throw new Error("unknown itemsSelecteMode " + itemsSelectMode);
+ throw new Error("unknown itemsSelectMode " + itemsSelectMode);
}
}
if(properties.progress != undefined){
@@ -191,9 +191,17 @@ module.exports = function(__runtime__, scope){
if(properties.checkBoxPrompt != undefined || properties.checkBoxChecked != undefined){
builder.checkBoxPrompt(wrapNonNullString(properties.checkBoxPrompt), !!properties.checkBoxChecked,
function(view, checked){
- builder.emit("check", checked, builder.getDialog());
+ builder.getDialog().emit("check", checked, builder.getDialog());
});
}
+ if(properties.customView != undefined) {
+ let customView = properties.customView;
+ if(typeof(customView) == 'xml' || typeof(customView) == 'string') {
+ customView = ui.run(() => ui.inflate(customView));
+ }
+ let wrapInScrollView = (properties.wrapInScrollView === undefined) ? true : properties.wrapInScrollView;
+ builder.customView(customView, wrapInScrollView);
+ }
}
function wrapNonNullString(str){
diff --git a/autojs/src/main/assets/modules/__engines__.js b/autojs/src/main/assets/modules/__engines__.js
index 9c428c785..a8104e42c 100644
--- a/autojs/src/main/assets/modules/__engines__.js
+++ b/autojs/src/main/assets/modules/__engines__.js
@@ -37,7 +37,7 @@ module.exports = function(__runtime__, scope){
}
config.delay = c.delay || 0;
config.interval = c.interval || 0;
- config.loopTimes = c.loopTimes || 1;
+ config.loopTimes = (c.loopTimes === undefined)? 1 : c.loopTimes;
if(c.arguments){
var arguments = c.arguments;
for(var key in arguments){
diff --git a/autojs/src/main/assets/modules/__ui__.js b/autojs/src/main/assets/modules/__ui__.js
index f9fcb9a07..c0dec7735 100644
--- a/autojs/src/main/assets/modules/__ui__.js
+++ b/autojs/src/main/assets/modules/__ui__.js
@@ -11,7 +11,7 @@ module.exports = function (runtime, global) {
ui.__defineGetter__("emitter", ()=> activity ? activity.getEventEmitter() : null);
ui.layout = function (xml) {
- if(!activity){
+ if(typeof(activity) == 'undefined'){
throw new Error("需要在ui模式下运行才能使用该函数");
}
runtime.ui.layoutInflater.setContext(activity);
@@ -24,15 +24,18 @@ module.exports = function (runtime, global) {
}
ui.inflate = function(xml, parent, attachToParent){
- if(!activity){
- throw new Error("需要在ui模式下运行才能使用该函数");
- }
if(typeof(xml) == 'xml'){
xml = xml.toXMLString();
}
parent = parent || null;
attachToParent = !!attachToParent;
- runtime.ui.layoutInflater.setContext(activity);
+ let ctx;
+ if(typeof(activity) == 'undefined') {
+ ctx = new android.view.ContextThemeWrapper(context, com.stardust.autojs.R.style.ScriptTheme);
+ } else {
+ ctx = activity;
+ }
+ runtime.ui.layoutInflater.setContext(ctx);
return runtime.ui.layoutInflater.inflate(xml.toString(), parent, attachToParent);
}
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
deleted file mode 100644
index e442ab9d5..000000000
--- a/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvasView.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package com.stardust.autojs.core.graphics;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-import com.stardust.autojs.core.eventloop.EventEmitter;
-import com.stardust.autojs.runtime.ScriptRuntime;
-import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
-
-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;
- private ScriptRuntime mScriptRuntime;
- private volatile long mTimePerDraw = 1000 / 30;
-
- public ScriptCanvasView(Context context, ScriptRuntime scriptRuntime) {
- super(context);
- mScriptRuntime = scriptRuntime;
- mEventEmitter = new EventEmitter(mScriptRuntime.bridges);
- mHolder = getHolder();
- init();
- }
-
-
- public void setMaxFps(int maxFps) {
- if (maxFps <= 0) {
- mTimePerDraw = 0;
- } else {
- mTimePerDraw = 100 / maxFps;
- }
- }
-
- private void init() {
- mHolder.addCallback(this);
- setZOrderOnTop(false);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- performDraw();
- Log.d(LOG_TAG, "surfaceCreated: " + this);
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-
- }
-
- private synchronized void performDraw() {
- if (mDrawingThreadPool != null)
- return;
- mDrawingThreadPool = Executors.newCachedThreadPool();
- mDrawingThreadPool.execute(() -> {
- Canvas canvas = null;
- SurfaceHolder holder = getHolder();
- long time = SystemClock.uptimeMillis();
- ScriptCanvas scriptCanvas = new ScriptCanvas();
- try {
- while (mDrawing) {
- canvas = holder.lockCanvas();
- scriptCanvas.setCanvas(canvas);
- scriptCanvas.drawColor(Color.WHITE);
- emit("draw", scriptCanvas, ScriptCanvasView.this);
- holder.unlockCanvasAndPost(canvas);
- canvas = null;
- long dt = mTimePerDraw - (SystemClock.uptimeMillis() - time);
- if (dt > 0) {
- sleep(dt);
- }
- time = SystemClock.uptimeMillis();
- }
- } catch (Exception e) {
- mScriptRuntime.exit(e);
- mDrawing = false;
- } finally {
- if (canvas != null) {
- holder.unlockCanvasAndPost(canvas);
- }
- }
- });
- }
-
- private void sleep(long dt) {
- try {
- Thread.sleep(dt);
- } catch (InterruptedException e) {
- throw new ScriptInterruptedException(e);
- }
- }
-
- @Override
- protected void onWindowVisibilityChanged(int visibility) {
- Log.d(LOG_TAG, "onWindowVisibilityChanged: " + this + ": visibility=" + visibility + ", mDrawingThreadPool=" + mDrawingThreadPool);
- if (visibility == VISIBLE) {
- mDrawing = true;
- } else {
- mDrawing = false;
- }
- super.onWindowVisibilityChanged(visibility);
- }
-
- @Override
- public synchronized void surfaceDestroyed(SurfaceHolder holder) {
- mDrawing = false;
- mDrawingThreadPool.shutdown();
- mDrawingThreadPool = null;
- Log.d(LOG_TAG, "surfaceDestroyed: " + this);
- }
-
- 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/graphics/ScriptCanvasView.kt b/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvasView.kt
new file mode 100644
index 000000000..dcf3e5a11
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvasView.kt
@@ -0,0 +1,178 @@
+package com.stardust.autojs.core.graphics
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.SurfaceTexture
+import android.os.SystemClock
+import android.util.Log
+import android.view.TextureView
+import android.view.View
+import com.stardust.autojs.core.eventloop.EventEmitter
+import com.stardust.autojs.runtime.ScriptRuntime
+import com.stardust.autojs.runtime.exception.ScriptInterruptedException
+import com.stardust.ext.ifNull
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+/**
+ * Created by Stardust on 2018/3/16.
+ */
+
+@SuppressLint("ViewConstructor")
+class ScriptCanvasView(context: Context, private val mScriptRuntime: ScriptRuntime) : TextureView(context), TextureView.SurfaceTextureListener {
+ @Volatile
+ private var mDrawing = true
+ private val mEventEmitter: EventEmitter = EventEmitter(mScriptRuntime.bridges)
+ private var mDrawingThreadPool: ExecutorService? = null
+ @Volatile
+ private var mTimePerDraw = (1000 / 30).toLong()
+
+ val maxListeners: Int
+ get() = mEventEmitter.maxListeners
+
+ init {
+ surfaceTextureListener = this
+ }
+
+ fun setMaxFps(maxFps: Int) {
+ mTimePerDraw = if (maxFps <= 0) {
+ 0
+ } else {
+ (100 / maxFps).toLong()
+ }
+ }
+
+ @Synchronized
+ private fun performDraw() {
+ ::mDrawingThreadPool.ifNull {
+ Executors.newCachedThreadPool()
+ }.run {
+ execute {
+ var canvas: Canvas? = null
+ var time = SystemClock.uptimeMillis()
+ val scriptCanvas = ScriptCanvas()
+ try {
+ while (mDrawing) {
+ canvas = lockCanvas()
+ scriptCanvas.setCanvas(canvas)
+ // scriptCanvas.drawColor(Color.WHITE);
+ emit("draw", scriptCanvas, this@ScriptCanvasView)
+ unlockCanvasAndPost(canvas)
+ canvas = null
+ val dt = mTimePerDraw - (SystemClock.uptimeMillis() - time)
+ if (dt > 0) {
+ sleep(dt)
+ }
+ time = SystemClock.uptimeMillis()
+ }
+ } catch (e: Exception) {
+ mScriptRuntime.exit(e)
+ mDrawing = false
+ } finally {
+ if (canvas != null) {
+ unlockCanvasAndPost(canvas)
+ }
+ }
+ }
+ }
+ }
+
+ private fun sleep(dt: Long) {
+ try {
+ Thread.sleep(dt)
+ } catch (e: InterruptedException) {
+ throw ScriptInterruptedException(e)
+ }
+
+ }
+
+ override fun onWindowVisibilityChanged(visibility: Int) {
+ Log.d(LOG_TAG, "onWindowVisibilityChanged: " + this + ": visibility=" + visibility + ", mDrawingThreadPool=" + mDrawingThreadPool)
+ val oldDrawing = mDrawing
+ mDrawing = visibility == View.VISIBLE
+ if (!oldDrawing && mDrawing) {
+ performDraw()
+ }
+ super.onWindowVisibilityChanged(visibility)
+ }
+
+ fun once(eventName: String, listener: Any): EventEmitter {
+ return mEventEmitter.once(eventName, listener)
+ }
+
+ fun on(eventName: String, listener: Any): EventEmitter {
+ return mEventEmitter.on(eventName, listener)
+ }
+
+ fun addListener(eventName: String, listener: Any): EventEmitter {
+ return mEventEmitter.addListener(eventName, listener)
+ }
+
+ fun emit(eventName: String, vararg args: Any): Boolean {
+ return mEventEmitter.emit(eventName, *args)
+ }
+
+ fun eventNames(): Array {
+ return mEventEmitter.eventNames()
+ }
+
+ fun listenerCount(eventName: String): Int {
+ return mEventEmitter.listenerCount(eventName)
+ }
+
+ fun listeners(eventName: String): Array {
+ return mEventEmitter.listeners(eventName)
+ }
+
+ fun prependListener(eventName: String, listener: Any): EventEmitter {
+ return mEventEmitter.prependListener(eventName, listener)
+ }
+
+ fun prependOnceListener(eventName: String, listener: Any): EventEmitter {
+ return mEventEmitter.prependOnceListener(eventName, listener)
+ }
+
+ fun removeAllListeners(): EventEmitter {
+ return mEventEmitter.removeAllListeners()
+ }
+
+ fun removeAllListeners(eventName: String): EventEmitter {
+ return mEventEmitter.removeAllListeners(eventName)
+ }
+
+ fun removeListener(eventName: String, listener: Any): EventEmitter {
+ return mEventEmitter.removeListener(eventName, listener)
+ }
+
+ fun setMaxListeners(n: Int): EventEmitter {
+ return mEventEmitter.setMaxListeners(n)
+ }
+
+ override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
+ performDraw()
+ Log.d(LOG_TAG, "onSurfaceTextureAvailable: ${this}, width = $width, height = $height")
+ }
+
+ override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {}
+
+ override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
+ mDrawing = false
+ mDrawingThreadPool?.shutdown()
+ Log.d(LOG_TAG, "onSurfaceTextureDestroyed: ${this}")
+ return true
+ }
+
+ override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
+
+ }
+
+ companion object {
+
+ private const val LOG_TAG = "ScriptCanvasView"
+
+ fun defaultMaxListeners(): Int {
+ return EventEmitter.defaultMaxListeners()
+ }
+ }
+}
diff --git a/autojs/src/main/java/com/stardust/autojs/core/http/MutableOkHttp.java b/autojs/src/main/java/com/stardust/autojs/core/http/MutableOkHttp.java
index f80c5ed5f..1d4f607e7 100644
--- a/autojs/src/main/java/com/stardust/autojs/core/http/MutableOkHttp.java
+++ b/autojs/src/main/java/com/stardust/autojs/core/http/MutableOkHttp.java
@@ -1,5 +1,6 @@
package com.stardust.autojs.core.http;
+import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
@@ -19,13 +20,24 @@ public class MutableOkHttp extends OkHttpClient {
private long mTimeout = 30 * 1000;
private Interceptor mRetryInterceptor = chain -> {
Request request = chain.request();
- Response response = chain.proceed(request);
+ Response response = null;
int tryCount = 0;
- while (!response.isSuccessful() && tryCount < getMaxRetries()) {
+ do {
+ boolean succeed;
+ try {
+ response = chain.proceed(request);
+ succeed = response.isSuccessful();
+ } catch (SocketTimeoutException e) {
+ succeed = false;
+ if (tryCount >= getMaxRetries()) {
+ throw e;
+ }
+ }
+ if (succeed || tryCount >= getMaxRetries()) {
+ return response;
+ }
tryCount++;
- response = chain.proceed(request);
- }
- return response;
+ } while (true);
};
public MutableOkHttp() {
@@ -64,6 +76,7 @@ public long getTimeout() {
public void setTimeout(long timeout) {
+ mTimeout = timeout;
muteClient();
}
diff --git a/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java b/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java
index 31b402f0d..c7cd424fc 100644
--- a/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java
+++ b/autojs/src/main/java/com/stardust/autojs/core/looper/Loopers.java
@@ -17,10 +17,13 @@
import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArrayList;
+import androidx.annotation.Nullable;
+
/**
* Created by Stardust on 2017/7/29.
*/
+@SuppressWarnings("ConstantConditions")
public class Loopers implements MessageQueue.IdleHandler {
private static final String LOG_TAG = "Loopers";
@@ -32,9 +35,27 @@ public interface LooperQuitHandler {
private static final Runnable EMPTY_RUNNABLE = () -> {
};
- private volatile ThreadLocal waitWhenIdle = new ThreadLocal<>();
- private volatile ThreadLocal> waitIds = new ThreadLocal<>();
- private volatile ThreadLocal maxWaitId = new ThreadLocal<>();
+ private volatile ThreadLocal waitWhenIdle = new ThreadLocal() {
+ @Nullable
+ @Override
+ protected Boolean initialValue() {
+ return Looper.myLooper() == Looper.getMainLooper();
+ }
+ };
+ private volatile ThreadLocal> waitIds = new ThreadLocal>() {
+ @Nullable
+ @Override
+ protected HashSet initialValue() {
+ return new HashSet<>();
+ }
+ };
+ private volatile ThreadLocal maxWaitId = new ThreadLocal() {
+ @Nullable
+ @Override
+ protected Integer initialValue() {
+ return 0;
+ }
+ };
private volatile ThreadLocal> looperQuitHandlers = new ThreadLocal<>();
private volatile Looper mServantLooper;
private Timers mTimers;
@@ -126,7 +147,7 @@ public Looper getServantLooper() {
return mServantLooper;
}
- public void quitServantLooper() {
+ private void quitServantLooper() {
if (mServantLooper == null)
return;
mServantLooper.quit();
@@ -134,12 +155,14 @@ public void quitServantLooper() {
public int waitWhenIdle() {
int id = maxWaitId.get();
+ Log.d(LOG_TAG, "waitWhenIdle: " + id);
maxWaitId.set(id + 1);
waitIds.get().add(id);
return id;
}
public void doNotWaitWhenIdle(int waitId) {
+ Log.d(LOG_TAG, "doNotWaitWhenIdle: " + waitId);
waitIds.get().remove(waitId);
}
@@ -181,9 +204,6 @@ public void prepare() {
if (Looper.myLooper() == null)
LooperHelper.prepare();
Looper.myQueue().addIdleHandler(this);
- waitWhenIdle.set(Looper.myLooper() == Looper.getMainLooper());
- waitIds.set(new HashSet<>());
- maxWaitId.set(0);
}
public void notifyThreadExit(TimerThread thread) {
diff --git a/autojs/src/main/java/com/stardust/autojs/core/looper/Timer.java b/autojs/src/main/java/com/stardust/autojs/core/looper/Timer.java
index 324c16b6e..032181863 100644
--- a/autojs/src/main/java/com/stardust/autojs/core/looper/Timer.java
+++ b/autojs/src/main/java/com/stardust/autojs/core/looper/Timer.java
@@ -89,6 +89,10 @@ public void postDelayed(Runnable r, long interval) {
}
}
+ public void post(Runnable r) {
+
+ }
+
public boolean clearInterval(int id) {
return clearCallback(id);
}
diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java
index e089536fa..5dc2ff131 100644
--- a/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java
+++ b/autojs/src/main/java/com/stardust/autojs/core/ui/dialog/JsDialogBuilder.java
@@ -34,7 +34,7 @@ public JsDialogBuilder(Context context, ScriptRuntime runtime) {
super(context);
mTimer = runtime.timers.getTimerForCurrentThread();
mLoopers = runtime.loopers;
- mEmitter = new EventEmitter(runtime.bridges, mTimer);
+ mEmitter = new EventEmitter(runtime.bridges);
mUiHandler = runtime.uiHandler;
setUpEvents();
}
@@ -70,7 +70,6 @@ private void setUpEvents() {
public void onShowCalled() {
mTimer.postDelayed(() -> mWaitId = mLoopers.waitWhenIdle(), 0);
-
}
public JsDialog getDialog() {
diff --git a/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java b/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java
index 8e49ec784..c1a44a2b1 100644
--- a/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java
+++ b/autojs/src/main/java/com/stardust/autojs/core/util/Shell.java
@@ -5,18 +5,13 @@
import android.preference.PreferenceManager;
import android.util.Log;
+import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
-import com.stardust.autojs.runtime.ScriptRuntime;
-import com.stardust.lang.ThreadCompat;
import com.stardust.pio.UncheckedIOException;
-import java.io.BufferedReader;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
+import java.util.ArrayList;
import jackpal.androidterm.ShellTermSession;
import jackpal.androidterm.emulatorview.TermSession;
@@ -68,9 +63,11 @@ public void onInterrupted(InterruptedException e) {
private volatile TermSession mTermSession;
private final Object mInitLock = new Object();
private final Object mExitLock = new Object();
+ private final Object mCommandOutputLock = new Object();
private volatile RuntimeException mInitException;
private volatile boolean mInitialized = false;
private volatile boolean mWaitingExit = false;
+ private volatile String mCommandOutput = null;
private final boolean mShouldReadOutput;
private Callback mCallback;
@@ -114,6 +111,18 @@ public void exec(String command) {
mTermSession.write(command + "\n");
}
+ public String execAndWaitFor(String command) {
+ exec(command);
+ synchronized (mCommandOutputLock) {
+ try {
+ mCommandOutputLock.wait();
+ return mCommandOutput;
+ } catch (InterruptedException e) {
+ throw new ScriptInterruptedException();
+ }
+ }
+ }
+
public void setCallback(Callback callback) {
mCallback = callback;
}
@@ -131,13 +140,13 @@ private void ensureInitialized() {
checkInitException();
throw new IllegalStateException();
}
- }else {
+ } else {
logDebug("ensureInitialized: init");
}
}
- private void logDebug(String log){
- if(DEBUG){
+ private void logDebug(String log) {
+ if (DEBUG) {
Log.d(TAG, log);
}
}
@@ -150,7 +159,7 @@ private void checkInitException() {
private void waitInitialization() {
synchronized (mInitLock) {
- if(mInitialized){
+ if (mInitialized) {
return;
}
logDebug("waitInitialization: enter");
@@ -204,33 +213,11 @@ public TermSession getTermSession() {
private class MyShellTermSession extends ShellTermSession {
- private BufferedReader mBufferedReader;
- private OutputStream mOutputStream;
- private Thread mReadingThread;
+ private StringBuilder mStringBuffer = new StringBuilder();
+ private ArrayList mCommandOutputs = new ArrayList<>();
public MyShellTermSession(TermSettings settings, String initialCommand) throws IOException {
super(settings, initialCommand);
- PipedInputStream pipedInputStream = new PipedInputStream(8192);
- mBufferedReader = new BufferedReader(new InputStreamReader(pipedInputStream));
- mOutputStream = new PipedOutputStream(pipedInputStream);
- if (mShouldReadOutput) {
- startReadingThread();
- }
- }
-
- private void startReadingThread() {
- mReadingThread = new ThreadCompat(() -> {
- String line;
- try {
- while (!Thread.currentThread().isInterrupted()
- && (line = mBufferedReader.readLine()) != null) {
- onNewLine(line);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- });
- mReadingThread.start();
}
private void onNewLine(String line) {
@@ -239,6 +226,8 @@ private void onNewLine(String line) {
if (!isRoot() && line.endsWith(" $ sh")) {
notifyInitialized();
}
+ } else {
+ mCommandOutputs.add(line);
}
if (mCallback != null) {
mCallback.onNewLine(line);
@@ -248,28 +237,56 @@ private void onNewLine(String line) {
}
}
- private void onOutput(String str){
+ private void onCommandOutput(ArrayList output) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 1; i < output.size(); i++) {
+ result.append(output.get(i));
+ if (i < output.size() - 1) {
+ result.append("\n");
+ }
+ }
+ logDebug("onCommandOutput: lines = " + output + ", output = " + result);
+ synchronized (mCommandOutputLock) {
+ mCommandOutput = result.toString();
+ mCommandOutputLock.notifyAll();
+ }
+ }
+
+ private void onOutput(String str) {
logDebug("onOutput: " + str);
if (!mInitialized) {
if (isRoot() && str.endsWith(":/ # ")) {
notifyInitialized();
}
}
+ int start = 0;
+ int i;
+ while (true) {
+ i = str.indexOf("\n", start);
+ if (i > 0) {
+ onNewLine((mStringBuffer.toString() + str.substring(0, i - 1)).trim());
+ mStringBuffer.delete(0, mStringBuffer.length());
+ } else {
+ if (start <= str.length() - 1) {
+ mStringBuffer.append(str.substring(start));
+ }
+ break;
+ }
+ start = i + 1;
+ }
+ if (str.endsWith(" # ") || str.endsWith(" $ ")) {
+ onCommandOutput(mCommandOutputs);
+ mCommandOutputs.clear();
+ }
if (mCallback != null) {
- mCallback.onOutput(str);
+ mCallback.onOutput(str.replace("\r", ""));
}
}
@Override
protected void processInput(byte[] data, int offset, int count) {
- try {
- onOutput(new String(data, offset, count));
- mOutputStream.write(data, offset, count);
- } catch (IOException e) {
- e.printStackTrace();
- finish();
- }
+ onOutput(new String(data, offset, count));
}
private void notifyExit() {
@@ -299,21 +316,6 @@ protected void onProcessExit() {
}
}
- @Override
- public void finish() {
- super.finish();
- if (!mShouldReadOutput)
- return;
- if(mReadingThread != null){
- mReadingThread.interrupt();
- }
- try {
- mBufferedReader.close();
- mOutputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
}
}
diff --git a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt
index d2d5f25c4..d8bdde59f 100644
--- a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt
+++ b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.kt
@@ -68,7 +68,7 @@ open class RhinoJavaScriptEngine(private val mAndroidContext: android.content.Co
runtime.topLevelScope = mScriptable
}
- public override fun doExecution(source: JavaScriptSource): Any {
+ public override fun doExecution(source: JavaScriptSource): Any? {
var reader = source.nonNullScriptReader
try {
reader = preprocess(reader)
diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/AbstractShell.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/AbstractShell.java
index 24911ec74..f0d17a5bf 100644
--- a/autojs/src/main/java/com/stardust/autojs/runtime/api/AbstractShell.java
+++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/AbstractShell.java
@@ -12,7 +12,6 @@
public abstract class AbstractShell {
-
public static class Result {
public int code = -1;
public String error;
diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java
index 14425ba1e..75d0ce72a 100644
--- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java
+++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Dialogs.java
@@ -144,7 +144,6 @@ public MaterialDialog.Builder newBuilder() {
}
return new JsDialogBuilder(context, mRuntime)
.theme(Theme.LIGHT);
-
}
public class NonUiDialogs {
diff --git a/automator/src/main/java/com/stardust/automator/search/DFS.kt b/automator/src/main/java/com/stardust/automator/search/DFS.kt
index 6f7efdd8a..005bd3fb7 100644
--- a/automator/src/main/java/com/stardust/automator/search/DFS.kt
+++ b/automator/src/main/java/com/stardust/automator/search/DFS.kt
@@ -2,6 +2,7 @@ package com.stardust.automator.search
import com.stardust.automator.UiObject
import com.stardust.automator.filter.Filter
+import java.util.*
import kotlin.collections.ArrayList
@@ -12,32 +13,26 @@ import kotlin.collections.ArrayList
object DFS : SearchAlgorithm {
override fun search(root: UiObject, filter: Filter, limit: Int): ArrayList {
- val list = ArrayList()
- if (filter.filter(root)) {
- list.add(root)
- if (list.size >= limit) {
- return list
+ val result = ArrayList()
+ val stack = LinkedList()
+ stack.push(root)
+ while (stack.isNotEmpty()) {
+ val parent = stack.pop()
+ for (i in parent.childCount - 1 downTo 0) {
+ val child = parent.child(i) ?: continue
+ stack.push(child)
}
- }
- searchChildren(root, list, filter, limit)
- return list
- }
-
- private fun searchChildren(parent: UiObject, list: MutableList, filter: Filter, limit: Int) {
- for (i in 0 until parent.childCount) {
- val child = parent.child(i) ?: continue
- val isTarget = filter.filter(child)
- if (isTarget) {
- list.add(child)
- if (list.size >= limit) {
+ if (filter.filter(parent)) {
+ result.add(parent)
+ if (result.size >= limit) {
break
}
- }
- searchChildren(child, list, filter, limit)
- if (!isTarget) {
- child.recycle()
+ } else {
+ if (parent !== root) {
+ parent.recycle()
+ }
}
}
+ return result
}
-
}
diff --git a/common/src/main/java/com/stardust/ext/Common.kt b/common/src/main/java/com/stardust/ext/Common.kt
new file mode 100644
index 000000000..b725e67c7
--- /dev/null
+++ b/common/src/main/java/com/stardust/ext/Common.kt
@@ -0,0 +1,13 @@
+package com.stardust.ext
+
+import kotlin.reflect.KMutableProperty0
+
+fun > T.ifNull(provider: () -> R): R {
+ val value = this.get()
+ if (value != null) {
+ return value
+ }
+ val newValue = provider()
+ set(newValue)
+ return newValue
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/stardust/io/ByteBufferBackedInputStream.kt b/common/src/main/java/com/stardust/io/ByteBufferBackedInputStream.kt
new file mode 100644
index 000000000..34b5fb74d
--- /dev/null
+++ b/common/src/main/java/com/stardust/io/ByteBufferBackedInputStream.kt
@@ -0,0 +1,30 @@
+package com.stardust.io
+
+import java.io.IOException
+import java.io.InputStream
+import java.nio.ByteBuffer
+
+class ByteBufferBackedInputStream(private var buf: ByteBuffer) : InputStream() {
+
+ @Throws(IOException::class)
+ override fun read(): Int {
+ return if (!buf.hasRemaining()) {
+ -1
+ } else buf.get().toInt() and 0xFF
+ }
+
+ @Throws(IOException::class)
+ override fun read(bytes: ByteArray, off: Int, len: Int): Int {
+ if (!buf.hasRemaining()) {
+ return -1
+ }
+ val read = Math.min(len, available())
+ buf.get(bytes, off, read)
+ buf.position(buf.position() - read)
+ return read
+ }
+
+ override fun available(): Int {
+ return buf.position()
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/com/stardust/io/ByteBufferBackedOutputStream.kt b/common/src/main/java/com/stardust/io/ByteBufferBackedOutputStream.kt
new file mode 100644
index 000000000..7c3ee425d
--- /dev/null
+++ b/common/src/main/java/com/stardust/io/ByteBufferBackedOutputStream.kt
@@ -0,0 +1,19 @@
+package com.stardust.io
+
+import java.io.IOException
+import java.io.OutputStream
+import java.nio.ByteBuffer
+
+class ByteBufferBackedOutputStream(private var buf: ByteBuffer) : OutputStream() {
+
+ @Throws(IOException::class)
+ override fun write(b: Int) {
+ buf.put(b.toByte())
+ }
+
+ @Throws(IOException::class)
+ override fun write(bytes: ByteArray, off: Int, len: Int) {
+ buf.put(bytes, off, len)
+ }
+
+}
\ No newline at end of file
diff --git a/inrt/src/main/assets/project/main.js b/inrt/src/main/assets/project/main.js
index bbb7dc698..b89ececfb 100644
--- a/inrt/src/main/assets/project/main.js
+++ b/inrt/src/main/assets/project/main.js
@@ -1 +1 @@
-Y?Mz
\ No newline at end of file
+toast("Hello, Auto.js");
\ No newline at end of file
diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/SettingsActivity.kt b/inrt/src/main/java/com/stardust/auojs/inrt/SettingsActivity.kt
index b2fffe43a..02efc172e 100644
--- a/inrt/src/main/java/com/stardust/auojs/inrt/SettingsActivity.kt
+++ b/inrt/src/main/java/com/stardust/auojs/inrt/SettingsActivity.kt
@@ -24,7 +24,7 @@ class SettingsActivity : AppCompatActivity() {
val toolbar = findViewById(R.id.toolbar)
toolbar.setTitle(R.string.text_settings)
setSupportActionBar(toolbar)
- toolbar.setNavigationOnClickListener { v -> finish() }
+ toolbar.setNavigationOnClickListener { finish() }
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/XJavaScriptEngine.kt b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/XJavaScriptEngine.kt
index ea55a42c8..75e954813 100644
--- a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/XJavaScriptEngine.kt
+++ b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/XJavaScriptEngine.kt
@@ -17,22 +17,28 @@ class XJavaScriptEngine(context: Context) : LoopBasedJavaScriptEngine(context) {
override fun execute(source: ScriptSource, callback: ExecuteCallback?) {
if (source is JavaScriptFileSource) {
try {
- execute(source.file)
+ if (execute(source.file)) {
+ return
+ }
} catch (e: Throwable) {
e.printStackTrace()
+ return
}
- } else {
- super.execute(source, callback)
}
+ super.execute(source, callback)
}
- private fun execute(file: File) {
+ private fun execute(file: File): Boolean {
val bytes = PFiles.readBytes(file.path)
+ if (!EncryptedScriptFileHeader.isValidFile(bytes)) {
+ return false
+ }
try {
super.execute(StringScriptSource(file.name, String(ScriptEncryption.decrypt(bytes, EncryptedScriptFileHeader.BLOCK_SIZE))))
} catch (e: GeneralSecurityException) {
e.printStackTrace()
}
+ return true
}
}
\ No newline at end of file
diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.kt b/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.kt
index 96c9e991e..5adbbe31b 100644
--- a/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.kt
+++ b/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.kt
@@ -70,7 +70,7 @@ open class AssetsProjectLauncher(private val mAssetsProjectDir: String, private
val source = JavaScriptFileSource("main", mMainScriptFile)
val config = ExecutionConfig(workingDirectory = mProjectDir)
if (source.executionMode and JavaScriptSource.EXECUTION_MODE_UI != 0) {
- config.intentFlags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NO_HISTORY
+ config.intentFlags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_TASK_ON_HOME
} else {
activity?.finish()
}