# Conflicts:
#	.idea/caches/build_file_checksums.ser
This commit is contained in:
hyb1996
2019-01-22 20:56:25 +08:00
31 changed files with 443 additions and 330 deletions

View File

@@ -11,6 +11,7 @@
<w>loopers</w> <w>loopers</w>
<w>opencv</w> <w>opencv</w>
<w>prefill</w> <w>prefill</w>
<w>recents</w>
<w>scriptable</w> <w>scriptable</w>
<w>storages</w> <w>storages</w>
<w>tasker</w> <w>tasker</w>

View File

@@ -1 +1 @@
[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":203},"path":"inrt-release.apk","properties":{"packageId":"com.stardust.auojs.inrt","split":"","minSdkVersion":"17"}}] [{"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":{}}]

View File

@@ -5,7 +5,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_SedTORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/> <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
@@ -15,7 +15,7 @@
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
<!-- 非Auto.js运行必需不会主动申请某些脚本可以自行申请--> <!-- 非Auto.js运行必需不会主动申请某些脚本可以自行申请-->
@@ -85,6 +85,7 @@
android:name=".ui.edit.EditActivity_" android:name=".ui.edit.EditActivity_"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:multiprocess="true" android:multiprocess="true"
android:taskAffinity="org.autojs.autojs.edit"
android:theme="@style/EditorTheme"> android:theme="@style/EditorTheme">
</activity> </activity>
<activity android:name=".ui.settings.AboutActivity_"/> <activity android:name=".ui.settings.AboutActivity_"/>
@@ -275,6 +276,7 @@
<data android:mimeType="text/plain"/> <data android:mimeType="text/plain"/>
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name="com.stardust.notification.NotificationListenerService" android:name="com.stardust.notification.NotificationListenerService"
android:label="@string/app_name" android:label="@string/app_name"

View File

@@ -91,22 +91,22 @@ object Scripts {
} }
fun edit(file: ScriptFile) { fun edit(context: Context, file: ScriptFile) {
EditActivity.editFile(GlobalAppContext.get(), file.simplifiedName, file.path) EditActivity.editFile(context, file.simplifiedName, file.path)
} }
fun edit(path: String) { fun edit(context: Context, path: String) {
edit(ScriptFile(path)) edit(context, ScriptFile(path))
} }
fun run(file: ScriptFile): ScriptExecution? { fun run(file: ScriptFile): ScriptExecution? {
try { return try {
return AutoJs.getInstance().scriptEngineService.execute(file.toSource(), AutoJs.getInstance().scriptEngineService.execute(file.toSource(),
ExecutionConfig(workingDirectory = file.parent)) ExecutionConfig(workingDirectory = file.parent))
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
Toast.makeText(GlobalAppContext.get(), e.message, Toast.LENGTH_LONG).show() Toast.makeText(GlobalAppContext.get(), e.message, Toast.LENGTH_LONG).show()
return null null
} }
} }

View File

@@ -114,7 +114,7 @@ public class ScriptOperations {
} }
notifyFileCreated(mCurrentDirectory, new ScriptFile(path)); notifyFileCreated(mCurrentDirectory, new ScriptFile(path));
if (edit) if (edit)
Scripts.INSTANCE.edit(path); Scripts.INSTANCE.edit(mContext, path);
} else { } else {
showMessage(R.string.text_create_fail); showMessage(R.string.text_create_fail);
} }

View File

@@ -4,9 +4,12 @@ import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.view.ActionMode; import android.view.ActionMode;
import android.view.Menu; import android.view.Menu;
@@ -195,7 +198,15 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega
showExitConfirmDialog(); showExitConfirmDialog();
return; return;
} }
super.finish(); finishAndRemoveFromRecents();
}
private void finishAndRemoveFromRecents() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask();
} else {
finish();
}
} }
private void showExitConfirmDialog() { private void showExitConfirmDialog() {
@@ -207,9 +218,9 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega
.neutralText(R.string.text_exit_directly) .neutralText(R.string.text_exit_directly)
.onNegative((dialog, which) -> { .onNegative((dialog, which) -> {
mEditorView.saveFile(); mEditorView.saveFile();
EditActivity.super.finish(); finishAndRemoveFromRecents();
}) })
.onNeutral((dialog, which) -> EditActivity.super.finish()) .onNeutral((dialog, which) -> finishAndRemoveFromRecents())
.show(); .show();
} }
@@ -294,4 +305,5 @@ public class EditActivity extends BaseActivity implements OnActivityResultDelega
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mRequestPermissionCallbacks.onRequestPermissionsResult(requestCode, permissions, grantResults); mRequestPermissionCallbacks.onRequestPermissionsResult(requestCode, permissions, grantResults);
} }
} }

View File

@@ -557,7 +557,7 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR
@OnClick(R.id.edit) @OnClick(R.id.edit)
void edit() { void edit() {
Scripts.INSTANCE.edit(new ScriptFile(mExplorerItem.getPath())); Scripts.INSTANCE.edit(getContext(), new ScriptFile(mExplorerItem.getPath()));
notifyOperated(); notifyOperated();
} }

View File

@@ -75,7 +75,7 @@ public class CommunityWebView extends EWebView {
.subscribe(file -> .subscribe(file ->
Snackbar.make(CommunityWebView.this, getResources().getString(R.string.format_file_downloaded, file.getPath()) Snackbar.make(CommunityWebView.this, getResources().getString(R.string.format_file_downloaded, file.getPath())
, Snackbar.LENGTH_LONG) , 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(), .show(),
error -> { error -> {
error.printStackTrace(); error.printStackTrace();

View File

@@ -62,7 +62,7 @@ public class MyScriptListFragment extends ViewPagerFragment implements FloatingA
mExplorerView.setExplorer(Explorers.workspace(), ExplorerDirPage.createRoot(Pref.getScriptDirPath())); mExplorerView.setExplorer(Explorers.workspace(), ExplorerDirPage.createRoot(Pref.getScriptDirPath()));
mExplorerView.setOnItemClickListener((view, item) -> { mExplorerView.setOnItemClickListener((view, item) -> {
if (item.isEditable()) { if (item.isEditable()) {
Scripts.INSTANCE.edit(item.toScriptFile()); Scripts.INSTANCE.edit(getActivity(), item.toScriptFile());
} else { } else {
IntentUtil.viewFile(GlobalAppContext.get(), item.getPath(), AppFileProvider.AUTHORITY); IntentUtil.viewFile(GlobalAppContext.get(), item.getPath(), AppFileProvider.AUTHORITY);
} }

View File

@@ -9,8 +9,6 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@@ -18,18 +16,18 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; 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.AfterViews;
import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById; 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 org.autojs.autojs.workground.WrapContentGridLayoutManger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import androidx.recyclerview.widget.RecyclerView;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@@ -93,7 +91,7 @@ public class ShortcutIconSelectActivity extends BaseActivity {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT) startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT)
.setType("image/*"), 11209); .setType("image/*"), 11234);
return true; return true;
} }

View File

@@ -155,7 +155,7 @@ module.exports = function(__runtime__, scope){
builder.input(wrapNonNullString(properties.inputHint), wrapNonNullString(properties.inputPrefill), builder.input(wrapNonNullString(properties.inputHint), wrapNonNullString(properties.inputPrefill),
function(dialog, input){ function(dialog, input){
input = input.toString(); input = input.toString();
builder.emit("input_change", dialog, input); builder.dialog.emit("input_change", builder.dialog, input);
}) })
.alwaysCallInputCallback(); .alwaysCallInputCallback();
} }
@@ -163,23 +163,23 @@ module.exports = function(__runtime__, scope){
var itemsSelectMode = properties.itemsSelectMode; var itemsSelectMode = properties.itemsSelectMode;
if(itemsSelectMode == undefined || itemsSelectMode == 'select'){ if(itemsSelectMode == undefined || itemsSelectMode == 'select'){
builder.itemsCallback(function(dialog, view, position, text){ 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'){ }else if(itemsSelectMode == 'single'){
builder.itemsCallbackSingleChoice(properties.itemsSelectedIndex == undefined ? -1 : properties.itemsSelectedIndex, builder.itemsCallbackSingleChoice(properties.itemsSelectedIndex == undefined ? -1 : properties.itemsSelectedIndex,
function(dialog, view, which, text){ 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; return true;
}); });
}else if(itemsSelectMode == 'multi'){ }else if(itemsSelectMode == 'multi'){
builder.itemsCallbackMultiChoice(properties.itemsSelectedIndex == undefined ? null : properties.itemsSelectedIndex, builder.itemsCallbackMultiChoice(properties.itemsSelectedIndex == undefined ? null : properties.itemsSelectedIndex,
function(dialog, view, indices, texts){ function(dialog, view, indices, texts){
dialog.emit("multi_choice", toJsArray(indices, (l, i)=> parseInt(l.get(i)), builder.dialog.emit("multi_choice", toJsArray(indices, (l, i)=> parseInt(l.get(i)),
toJsArray(texts, (l, i)=> l.get(i).toString())), dialog); toJsArray(texts, (l, i)=> l.get(i).toString())), builder.dialog);
return true; return true;
}); });
}else{ }else{
throw new Error("unknown itemsSelecteMode " + itemsSelectMode); throw new Error("unknown itemsSelectMode " + itemsSelectMode);
} }
} }
if(properties.progress != undefined){ if(properties.progress != undefined){
@@ -191,9 +191,17 @@ module.exports = function(__runtime__, scope){
if(properties.checkBoxPrompt != undefined || properties.checkBoxChecked != undefined){ if(properties.checkBoxPrompt != undefined || properties.checkBoxChecked != undefined){
builder.checkBoxPrompt(wrapNonNullString(properties.checkBoxPrompt), !!properties.checkBoxChecked, builder.checkBoxPrompt(wrapNonNullString(properties.checkBoxPrompt), !!properties.checkBoxChecked,
function(view, checked){ 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){ function wrapNonNullString(str){

View File

@@ -37,7 +37,7 @@ module.exports = function(__runtime__, scope){
} }
config.delay = c.delay || 0; config.delay = c.delay || 0;
config.interval = c.interval || 0; config.interval = c.interval || 0;
config.loopTimes = c.loopTimes || 1; config.loopTimes = (c.loopTimes === undefined)? 1 : c.loopTimes;
if(c.arguments){ if(c.arguments){
var arguments = c.arguments; var arguments = c.arguments;
for(var key in arguments){ for(var key in arguments){

View File

@@ -11,7 +11,7 @@ module.exports = function (runtime, global) {
ui.__defineGetter__("emitter", ()=> activity ? activity.getEventEmitter() : null); ui.__defineGetter__("emitter", ()=> activity ? activity.getEventEmitter() : null);
ui.layout = function (xml) { ui.layout = function (xml) {
if(!activity){ if(typeof(activity) == 'undefined'){
throw new Error("需要在ui模式下运行才能使用该函数"); throw new Error("需要在ui模式下运行才能使用该函数");
} }
runtime.ui.layoutInflater.setContext(activity); runtime.ui.layoutInflater.setContext(activity);
@@ -24,15 +24,18 @@ module.exports = function (runtime, global) {
} }
ui.inflate = function(xml, parent, attachToParent){ ui.inflate = function(xml, parent, attachToParent){
if(!activity){
throw new Error("需要在ui模式下运行才能使用该函数");
}
if(typeof(xml) == 'xml'){ if(typeof(xml) == 'xml'){
xml = xml.toXMLString(); xml = xml.toXMLString();
} }
parent = parent || null; parent = parent || null;
attachToParent = !!attachToParent; 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); return runtime.ui.layoutInflater.inflate(xml.toString(), parent, attachToParent);
} }

View File

@@ -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();
}
}

View File

@@ -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<String> {
return mEventEmitter.eventNames()
}
fun listenerCount(eventName: String): Int {
return mEventEmitter.listenerCount(eventName)
}
fun listeners(eventName: String): Array<Any> {
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()
}
}
}

View File

@@ -1,5 +1,6 @@
package com.stardust.autojs.core.http; package com.stardust.autojs.core.http;
import java.net.SocketTimeoutException;
import java.util.Collections; import java.util.Collections;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -19,13 +20,24 @@ public class MutableOkHttp extends OkHttpClient {
private long mTimeout = 30 * 1000; private long mTimeout = 30 * 1000;
private Interceptor mRetryInterceptor = chain -> { private Interceptor mRetryInterceptor = chain -> {
Request request = chain.request(); Request request = chain.request();
Response response = chain.proceed(request); Response response = null;
int tryCount = 0; int tryCount = 0;
while (!response.isSuccessful() && tryCount < getMaxRetries()) { do {
tryCount++; boolean succeed;
try {
response = chain.proceed(request); response = chain.proceed(request);
succeed = response.isSuccessful();
} catch (SocketTimeoutException e) {
succeed = false;
if (tryCount >= getMaxRetries()) {
throw e;
} }
}
if (succeed || tryCount >= getMaxRetries()) {
return response; return response;
}
tryCount++;
} while (true);
}; };
public MutableOkHttp() { public MutableOkHttp() {
@@ -64,6 +76,7 @@ public class MutableOkHttp extends OkHttpClient {
public void setTimeout(long timeout) { public void setTimeout(long timeout) {
mTimeout = timeout;
muteClient(); muteClient();
} }

View File

@@ -17,10 +17,13 @@ import org.mozilla.javascript.Context;
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import androidx.annotation.Nullable;
/** /**
* Created by Stardust on 2017/7/29. * Created by Stardust on 2017/7/29.
*/ */
@SuppressWarnings("ConstantConditions")
public class Loopers implements MessageQueue.IdleHandler { public class Loopers implements MessageQueue.IdleHandler {
private static final String LOG_TAG = "Loopers"; private static final String LOG_TAG = "Loopers";
@@ -32,9 +35,27 @@ public class Loopers implements MessageQueue.IdleHandler {
private static final Runnable EMPTY_RUNNABLE = () -> { private static final Runnable EMPTY_RUNNABLE = () -> {
}; };
private volatile ThreadLocal<Boolean> waitWhenIdle = new ThreadLocal<>(); private volatile ThreadLocal<Boolean> waitWhenIdle = new ThreadLocal<Boolean>() {
private volatile ThreadLocal<HashSet<Integer>> waitIds = new ThreadLocal<>(); @Nullable
private volatile ThreadLocal<Integer> maxWaitId = new ThreadLocal<>(); @Override
protected Boolean initialValue() {
return Looper.myLooper() == Looper.getMainLooper();
}
};
private volatile ThreadLocal<HashSet<Integer>> waitIds = new ThreadLocal<HashSet<Integer>>() {
@Nullable
@Override
protected HashSet<Integer> initialValue() {
return new HashSet<>();
}
};
private volatile ThreadLocal<Integer> maxWaitId = new ThreadLocal<Integer>() {
@Nullable
@Override
protected Integer initialValue() {
return 0;
}
};
private volatile ThreadLocal<CopyOnWriteArrayList<LooperQuitHandler>> looperQuitHandlers = new ThreadLocal<>(); private volatile ThreadLocal<CopyOnWriteArrayList<LooperQuitHandler>> looperQuitHandlers = new ThreadLocal<>();
private volatile Looper mServantLooper; private volatile Looper mServantLooper;
private Timers mTimers; private Timers mTimers;
@@ -126,7 +147,7 @@ public class Loopers implements MessageQueue.IdleHandler {
return mServantLooper; return mServantLooper;
} }
public void quitServantLooper() { private void quitServantLooper() {
if (mServantLooper == null) if (mServantLooper == null)
return; return;
mServantLooper.quit(); mServantLooper.quit();
@@ -134,12 +155,14 @@ public class Loopers implements MessageQueue.IdleHandler {
public int waitWhenIdle() { public int waitWhenIdle() {
int id = maxWaitId.get(); int id = maxWaitId.get();
Log.d(LOG_TAG, "waitWhenIdle: " + id);
maxWaitId.set(id + 1); maxWaitId.set(id + 1);
waitIds.get().add(id); waitIds.get().add(id);
return id; return id;
} }
public void doNotWaitWhenIdle(int waitId) { public void doNotWaitWhenIdle(int waitId) {
Log.d(LOG_TAG, "doNotWaitWhenIdle: " + waitId);
waitIds.get().remove(waitId); waitIds.get().remove(waitId);
} }
@@ -181,9 +204,6 @@ public class Loopers implements MessageQueue.IdleHandler {
if (Looper.myLooper() == null) if (Looper.myLooper() == null)
LooperHelper.prepare(); LooperHelper.prepare();
Looper.myQueue().addIdleHandler(this); Looper.myQueue().addIdleHandler(this);
waitWhenIdle.set(Looper.myLooper() == Looper.getMainLooper());
waitIds.set(new HashSet<>());
maxWaitId.set(0);
} }
public void notifyThreadExit(TimerThread thread) { public void notifyThreadExit(TimerThread thread) {

View File

@@ -89,6 +89,10 @@ public class Timer {
} }
} }
public void post(Runnable r) {
}
public boolean clearInterval(int id) { public boolean clearInterval(int id) {
return clearCallback(id); return clearCallback(id);
} }

View File

@@ -34,7 +34,7 @@ public class JsDialogBuilder extends MaterialDialog.Builder {
super(context); super(context);
mTimer = runtime.timers.getTimerForCurrentThread(); mTimer = runtime.timers.getTimerForCurrentThread();
mLoopers = runtime.loopers; mLoopers = runtime.loopers;
mEmitter = new EventEmitter(runtime.bridges, mTimer); mEmitter = new EventEmitter(runtime.bridges);
mUiHandler = runtime.uiHandler; mUiHandler = runtime.uiHandler;
setUpEvents(); setUpEvents();
} }
@@ -70,7 +70,6 @@ public class JsDialogBuilder extends MaterialDialog.Builder {
public void onShowCalled() { public void onShowCalled() {
mTimer.postDelayed(() -> mWaitId = mLoopers.waitWhenIdle(), 0); mTimer.postDelayed(() -> mWaitId = mLoopers.waitWhenIdle(), 0);
} }
public JsDialog getDialog() { public JsDialog getDialog() {

View File

@@ -5,18 +5,13 @@ import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.runtime.api.AbstractShell; import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.lang.ThreadCompat;
import com.stardust.pio.UncheckedIOException; import com.stardust.pio.UncheckedIOException;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.util.ArrayList;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import jackpal.androidterm.ShellTermSession; import jackpal.androidterm.ShellTermSession;
import jackpal.androidterm.emulatorview.TermSession; import jackpal.androidterm.emulatorview.TermSession;
@@ -68,9 +63,11 @@ public class Shell extends AbstractShell {
private volatile TermSession mTermSession; private volatile TermSession mTermSession;
private final Object mInitLock = new Object(); private final Object mInitLock = new Object();
private final Object mExitLock = new Object(); private final Object mExitLock = new Object();
private final Object mCommandOutputLock = new Object();
private volatile RuntimeException mInitException; private volatile RuntimeException mInitException;
private volatile boolean mInitialized = false; private volatile boolean mInitialized = false;
private volatile boolean mWaitingExit = false; private volatile boolean mWaitingExit = false;
private volatile String mCommandOutput = null;
private final boolean mShouldReadOutput; private final boolean mShouldReadOutput;
private Callback mCallback; private Callback mCallback;
@@ -114,6 +111,18 @@ public class Shell extends AbstractShell {
mTermSession.write(command + "\n"); 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) { public void setCallback(Callback callback) {
mCallback = callback; mCallback = callback;
} }
@@ -131,13 +140,13 @@ public class Shell extends AbstractShell {
checkInitException(); checkInitException();
throw new IllegalStateException(); throw new IllegalStateException();
} }
}else { } else {
logDebug("ensureInitialized: init"); logDebug("ensureInitialized: init");
} }
} }
private void logDebug(String log){ private void logDebug(String log) {
if(DEBUG){ if (DEBUG) {
Log.d(TAG, log); Log.d(TAG, log);
} }
} }
@@ -150,7 +159,7 @@ public class Shell extends AbstractShell {
private void waitInitialization() { private void waitInitialization() {
synchronized (mInitLock) { synchronized (mInitLock) {
if(mInitialized){ if (mInitialized) {
return; return;
} }
logDebug("waitInitialization: enter"); logDebug("waitInitialization: enter");
@@ -204,33 +213,11 @@ public class Shell extends AbstractShell {
private class MyShellTermSession extends ShellTermSession { private class MyShellTermSession extends ShellTermSession {
private BufferedReader mBufferedReader; private StringBuilder mStringBuffer = new StringBuilder();
private OutputStream mOutputStream; private ArrayList<String> mCommandOutputs = new ArrayList<>();
private Thread mReadingThread;
public MyShellTermSession(TermSettings settings, String initialCommand) throws IOException { public MyShellTermSession(TermSettings settings, String initialCommand) throws IOException {
super(settings, initialCommand); 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) { private void onNewLine(String line) {
@@ -239,6 +226,8 @@ public class Shell extends AbstractShell {
if (!isRoot() && line.endsWith(" $ sh")) { if (!isRoot() && line.endsWith(" $ sh")) {
notifyInitialized(); notifyInitialized();
} }
} else {
mCommandOutputs.add(line);
} }
if (mCallback != null) { if (mCallback != null) {
mCallback.onNewLine(line); mCallback.onNewLine(line);
@@ -248,28 +237,56 @@ public class Shell extends AbstractShell {
} }
} }
private void onOutput(String str){ private void onCommandOutput(ArrayList<String> 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); logDebug("onOutput: " + str);
if (!mInitialized) { if (!mInitialized) {
if (isRoot() && str.endsWith(":/ # ")) { if (isRoot() && str.endsWith(":/ # ")) {
notifyInitialized(); 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) { if (mCallback != null) {
mCallback.onOutput(str); mCallback.onOutput(str.replace("\r", ""));
} }
} }
@Override @Override
protected void processInput(byte[] data, int offset, int count) { protected void processInput(byte[] data, int offset, int count) {
try {
onOutput(new String(data, offset, count)); onOutput(new String(data, offset, count));
mOutputStream.write(data, offset, count);
} catch (IOException e) {
e.printStackTrace();
finish();
}
} }
private void notifyExit() { private void notifyExit() {
@@ -299,21 +316,6 @@ public class Shell extends AbstractShell {
} }
} }
@Override
public void finish() {
super.finish();
if (!mShouldReadOutput)
return;
if(mReadingThread != null){
mReadingThread.interrupt();
}
try {
mBufferedReader.close();
mOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
} }

View File

@@ -68,7 +68,7 @@ open class RhinoJavaScriptEngine(private val mAndroidContext: android.content.Co
runtime.topLevelScope = mScriptable runtime.topLevelScope = mScriptable
} }
public override fun doExecution(source: JavaScriptSource): Any { public override fun doExecution(source: JavaScriptSource): Any? {
var reader = source.nonNullScriptReader var reader = source.nonNullScriptReader
try { try {
reader = preprocess(reader) reader = preprocess(reader)

View File

@@ -12,7 +12,6 @@ import com.stardust.util.ScreenMetrics;
public abstract class AbstractShell { public abstract class AbstractShell {
public static class Result { public static class Result {
public int code = -1; public int code = -1;
public String error; public String error;

View File

@@ -144,7 +144,6 @@ public class Dialogs {
} }
return new JsDialogBuilder(context, mRuntime) return new JsDialogBuilder(context, mRuntime)
.theme(Theme.LIGHT); .theme(Theme.LIGHT);
} }
public class NonUiDialogs { public class NonUiDialogs {

View File

@@ -2,6 +2,7 @@ package com.stardust.automator.search
import com.stardust.automator.UiObject import com.stardust.automator.UiObject
import com.stardust.automator.filter.Filter import com.stardust.automator.filter.Filter
import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@@ -12,32 +13,26 @@ import kotlin.collections.ArrayList
object DFS : SearchAlgorithm { object DFS : SearchAlgorithm {
override fun search(root: UiObject, filter: Filter, limit: Int): ArrayList<UiObject> { override fun search(root: UiObject, filter: Filter, limit: Int): ArrayList<UiObject> {
val list = ArrayList<UiObject>() val result = ArrayList<UiObject>()
if (filter.filter(root)) { val stack = LinkedList<UiObject>()
list.add(root) stack.push(root)
if (list.size >= limit) { while (stack.isNotEmpty()) {
return list val parent = stack.pop()
} for (i in parent.childCount - 1 downTo 0) {
}
searchChildren(root, list, filter, limit)
return list
}
private fun searchChildren(parent: UiObject, list: MutableList<UiObject>, filter: Filter, limit: Int) {
for (i in 0 until parent.childCount) {
val child = parent.child(i) ?: continue val child = parent.child(i) ?: continue
val isTarget = filter.filter(child) stack.push(child)
if (isTarget) { }
list.add(child) if (filter.filter(parent)) {
if (list.size >= limit) { result.add(parent)
if (result.size >= limit) {
break break
} }
} } else {
searchChildren(child, list, filter, limit) if (parent !== root) {
if (!isTarget) { parent.recycle()
child.recycle()
} }
} }
} }
return result
}
} }

View File

@@ -0,0 +1,13 @@
package com.stardust.ext
import kotlin.reflect.KMutableProperty0
fun <R, T : KMutableProperty0<R?>> T.ifNull(provider: () -> R): R {
val value = this.get()
if (value != null) {
return value
}
val newValue = provider()
set(newValue)
return newValue
}

View File

@@ -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()
}
}

View File

@@ -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)
}
}

View File

@@ -1 +1 @@
Yホ?<EFBFBD>Mコzォア toast("Hello, Auto.js");

View File

@@ -24,7 +24,7 @@ class SettingsActivity : AppCompatActivity() {
val toolbar = findViewById<Toolbar>(R.id.toolbar) val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.setTitle(R.string.text_settings) toolbar.setTitle(R.string.text_settings)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
toolbar.setNavigationOnClickListener { v -> finish() } toolbar.setNavigationOnClickListener { finish() }
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
} }

View File

@@ -17,22 +17,28 @@ class XJavaScriptEngine(context: Context) : LoopBasedJavaScriptEngine(context) {
override fun execute(source: ScriptSource, callback: ExecuteCallback?) { override fun execute(source: ScriptSource, callback: ExecuteCallback?) {
if (source is JavaScriptFileSource) { if (source is JavaScriptFileSource) {
try { try {
execute(source.file) if (execute(source.file)) {
return
}
} catch (e: Throwable) { } catch (e: Throwable) {
e.printStackTrace() 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) val bytes = PFiles.readBytes(file.path)
if (!EncryptedScriptFileHeader.isValidFile(bytes)) {
return false
}
try { try {
super.execute(StringScriptSource(file.name, String(ScriptEncryption.decrypt(bytes, EncryptedScriptFileHeader.BLOCK_SIZE)))) super.execute(StringScriptSource(file.name, String(ScriptEncryption.decrypt(bytes, EncryptedScriptFileHeader.BLOCK_SIZE))))
} catch (e: GeneralSecurityException) { } catch (e: GeneralSecurityException) {
e.printStackTrace() e.printStackTrace()
} }
return true
} }
} }

View File

@@ -70,7 +70,7 @@ open class AssetsProjectLauncher(private val mAssetsProjectDir: String, private
val source = JavaScriptFileSource("main", mMainScriptFile) val source = JavaScriptFileSource("main", mMainScriptFile)
val config = ExecutionConfig(workingDirectory = mProjectDir) val config = ExecutionConfig(workingDirectory = mProjectDir)
if (source.executionMode and JavaScriptSource.EXECUTION_MODE_UI != 0) { 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 { } else {
activity?.finish() activity?.finish()
} }