Merge branch 'dev' of https://github.com/hyb1996/NoRootScriptDroid into dev
# Conflicts: # .idea/caches/build_file_checksums.ser
This commit is contained in:
1
.idea/dictionaries/Stardust.xml
generated
1
.idea/dictionaries/Stardust.xml
generated
@@ -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>
|
||||||
|
|||||||
@@ -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":{}}]
|
||||||
@@ -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"/>
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -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,6 +237,21 @@ public class Shell extends AbstractShell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
private void onOutput(String str) {
|
||||||
logDebug("onOutput: " + str);
|
logDebug("onOutput: " + str);
|
||||||
if (!mInitialized) {
|
if (!mInitialized) {
|
||||||
@@ -255,21 +259,34 @@ public class Shell extends AbstractShell {
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
common/src/main/java/com/stardust/ext/Common.kt
Normal file
13
common/src/main/java/com/stardust/ext/Common.kt
Normal 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
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
Yホ?翔<EFBFBD>Mコzォア
|
toast("Hello, Auto.js");
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user