优化 脚本管理器增删文件后的更新

新增 支持插件
优化 多点找色的内存泄漏
修复 文件重命名时的后缀问题
修复 脚本抛出Throwable不能被捕捉的问题
This commit is contained in:
hyb1996
2018-10-23 15:00:34 +08:00
parent 2b71f5e856
commit 148784656d
38 changed files with 468 additions and 57 deletions

Binary file not shown.

View File

@@ -1,7 +1,7 @@
"ui"; "ui";
var ColoredButton = (function() { var ColoredButton = (function() {
//继承至ui.Widget //继承ui.Widget
util.extend(ColoredButton, ui.Widget); util.extend(ColoredButton, ui.Widget);
function ColoredButton() { function ColoredButton() {

View File

@@ -34,7 +34,7 @@ public class ScriptExecutionGlobalListener implements ScriptExecutionListener {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
onFinish(execution); onFinish(execution);
} }

View File

@@ -87,14 +87,14 @@ public class Explorer {
if (cachedParent != null) { if (cachedParent != null) {
cachedParent.addChild(item); cachedParent.addChild(item);
} }
mEventBus.post(new ExplorerChangeEvent(parent, CREATE, item)); mEventBus.post(new ExplorerChangeEvent(parent, CREATE, item, item));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void refreshAll() { public void refreshAll() {
if (mExplorerPageLruCache != null) if (mExplorerPageLruCache != null)
mExplorerPageLruCache.evictAll(); mExplorerPageLruCache.evictAll();
mEventBus.post(new ExplorerChangeEvent(ALL)); mEventBus.post(ExplorerChangeEvent.EVENT_ALL);
} }

View File

@@ -1,13 +1,18 @@
package org.autojs.autojs.model.explorer; package org.autojs.autojs.model.explorer;
import com.stardust.util.ObjectHelper;
public class ExplorerChangeEvent { public class ExplorerChangeEvent {
public static final int REMOVE = 0; public static final int REMOVE = 0;
public static final int CREATE = 1; public static final int CREATE = 1;
public static final int CHANGE = 2; public static final int CHANGE = 2;
public static final int ALL = 3; public static final int ALL = 3;
public static final int CHILDREN_CHANGE = 4; public static final int CHILDREN_CHANGE = 4;
public static final ExplorerChangeEvent EVENT_ALL = new ExplorerChangeEvent(ALL);
private final int mAction; private final int mAction;
private final ExplorerItem mItem; private final ExplorerItem mItem;
private final ExplorerItem mNewItem; private final ExplorerItem mNewItem;
@@ -21,10 +26,10 @@ public class ExplorerChangeEvent {
} }
public ExplorerChangeEvent(ExplorerPage parent, int action, ExplorerItem item) { public ExplorerChangeEvent(ExplorerPage parent, int action, ExplorerItem item) {
this(parent, action, item, null); this(parent, action, item, null);
} }
public ExplorerChangeEvent(int action) { private ExplorerChangeEvent(int action) {
this(null, action, null, null); this(null, action, null, null);
} }
@@ -43,4 +48,30 @@ public class ExplorerChangeEvent {
public ExplorerPage getPage() { public ExplorerPage getPage() {
return mPage; return mPage;
} }
@Override
public String toString() {
return "ExplorerChangeEvent{" +
"mAction=" + nameOfAction(mAction) +
", mPage=" + mPage +
", mItem=" + mItem +
", mNewItem=" + mNewItem +
'}';
}
private static String nameOfAction(int action) {
switch (action) {
case ALL:
return "ALL";
case CHANGE:
return "CHANGE";
case CREATE:
return "CREATE";
case REMOVE:
return "REMOVE";
case CHILDREN_CHANGE:
return "CHILDREN_CHANGE";
}
throw new IllegalArgumentException("action = " + action);
}
} }

View File

@@ -44,7 +44,7 @@ public class ExplorerDirPage extends ExplorerFileItem implements ExplorerPage {
@Override @Override
public ExplorerFileItem rename(String newName) { public ExplorerFileItem rename(String newName) {
return new ExplorerDirPage(getFile().renameAndReturnNewFile(newName), getParent()); return new ExplorerDirPage(getFile().renameTo(newName), getParent());
} }
protected int indexOf(ExplorerItem child){ protected int indexOf(ExplorerItem child){

View File

@@ -2,6 +2,7 @@ package org.autojs.autojs.model.explorer;
import com.stardust.pio.PFile; import com.stardust.pio.PFile;
import com.stardust.util.ObjectHelper; import com.stardust.util.ObjectHelper;
import com.stardust.util.Objects;
import org.autojs.autojs.model.script.ScriptFile; import org.autojs.autojs.model.script.ScriptFile;
@@ -71,7 +72,7 @@ public class ExplorerFileItem implements ExplorerItem {
} }
public ExplorerFileItem rename(String newName) { public ExplorerFileItem rename(String newName) {
return new ExplorerFileItem(mFile.renameAndReturnNewFile(newName), getParent()); return new ExplorerFileItem(mFile.renameTo(newName), getParent());
} }
@Override @Override
@@ -102,4 +103,24 @@ public class ExplorerFileItem implements ExplorerItem {
String type = getType(); String type = getType();
return type.equals("js") || type.equals("auto"); return type.equals("js") || type.equals("auto");
} }
@Override
public String toString() {
return getClass().getSimpleName() + "{" +
"mFile=" + mFile + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExplorerFileItem that = (ExplorerFileItem) o;
return Objects.equals(mFile, that.mFile);
}
@Override
public int hashCode() {
return Objects.hashCode(mFile);
}
} }

View File

@@ -30,6 +30,6 @@ public class ExplorerProjectPage extends ExplorerDirPage {
@Override @Override
public ExplorerFileItem rename(String newName) { public ExplorerFileItem rename(String newName) {
return new ExplorerProjectPage(getFile().renameAndReturnNewFile(newName), getParent(), mProjectConfig); return new ExplorerProjectPage(getFile().renameTo(newName), getParent(), mProjectConfig);
} }
} }

View File

@@ -52,7 +52,7 @@ public class Scripts {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
RhinoException rhinoException = getRhinoException(e); RhinoException rhinoException = getRhinoException(e);
int line = -1, col = 0; int line = -1, col = 0;
if (rhinoException != null) { if (rhinoException != null) {

View File

@@ -0,0 +1,61 @@
package org.autojs.autojs.ui.common;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.Editable;
import android.widget.EditText;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import org.autojs.autojs.R;
import java.io.File;
public class FileNameInputDialog implements MaterialDialog.InputCallback {
private String mExcluded;
private boolean mIsFirstTextChanged = true;
private String mExtension;
private Context mContext;
private File mDir;
private void validateInput(MaterialDialog dialog, String extension) {
EditText editText = dialog.getInputEditText();
if (editText == null)
return;
Editable input = editText.getText();
int errorResId = 0;
if (input == null || input.length() == 0) {
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
return;
}
if (new File(mDir, extension == null ? input.toString() : input.toString() + extension).exists()) {
errorResId = R.string.text_file_exists;
}
if (errorResId == 0) {
editText.setError(null);
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(true);
} else {
editText.setError(mContext.getString(errorResId));
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
}
}
@Override
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
if (mIsFirstTextChanged) {
mIsFirstTextChanged = false;
return;
}
EditText editText = dialog.getInputEditText();
if (editText == null)
return;
if (input.equals(mExcluded)) {
editText.setError(null);
dialog.getActionButton(DialogAction.POSITIVE).setEnabled(true);
return;
}
validateInput(dialog, mExtension);
}
}

View File

@@ -269,10 +269,8 @@ public class ScriptOperations {
} }
public Observable<ExplorerFileItem> rename(final ExplorerFileItem item) { public Observable<ExplorerFileItem> rename(final ExplorerFileItem item) {
final ScriptFile oldFile = new ScriptFile(item.getPath());
String originalName = item.getName(); String originalName = item.getName();
return showNameInputDialog(originalName, new InputCallback(oldFile.isDirectory() ? null : PFiles.getExtension(item.getName()), return showNameInputDialog(originalName, new InputCallback(null, originalName))
originalName))
.map(newName -> { .map(newName -> {
ExplorerFileItem newItem = item.rename(newName); ExplorerFileItem newItem = item.rename(newName);
if (ObjectHelper.equals(newItem.toScriptFile(), item.toScriptFile())) { if (ObjectHelper.equals(newItem.toScriptFile(), item.toScriptFile())) {
@@ -307,18 +305,23 @@ public class ScriptOperations {
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
public void deleteWithoutConfirm(final ScriptFile scriptFile) { public void deleteWithoutConfirm(final ScriptFile scriptFile) {
boolean isDir = scriptFile.isDirectory();
Observable.fromPublisher((Publisher<Boolean>) s -> s.onNext(PFiles.deleteRecursively(scriptFile))) Observable.fromPublisher((Publisher<Boolean>) s -> s.onNext(PFiles.deleteRecursively(scriptFile)))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(deleted -> { .subscribe(deleted -> {
showMessage(deleted ? R.string.text_already_delete : R.string.text_delete_failed); showMessage(deleted ? R.string.text_already_delete : R.string.text_delete_failed);
if (deleted) if (deleted)
notifyFileRemoved(mCurrentDirectory, scriptFile); notifyFileRemoved(isDir, scriptFile);
}); });
} }
private void notifyFileRemoved(ScriptFile directory, ScriptFile scriptFile) { private void notifyFileRemoved(boolean isDir, ScriptFile scriptFile) {
mExplorer.notifyItemRemoved(new ExplorerFileItem(scriptFile, mExplorerPage)); if (isDir) {
mExplorer.notifyItemRemoved(new ExplorerDirPage(scriptFile, mExplorerPage));
} else {
mExplorer.notifyItemRemoved(new ExplorerFileItem(scriptFile, mExplorerPage));
}
} }

View File

@@ -10,6 +10,7 @@ import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@@ -243,9 +244,40 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR
@Subscribe @Subscribe
public void onExplorerChange(ExplorerChangeEvent event) { public void onExplorerChange(ExplorerChangeEvent event) {
if ((event.getAction() == ExplorerChangeEvent.ALL) Log.d(LOG_TAG, "on explorer change: " + event);
|| mCurrentPageState.page.getPath().equals(event.getPage().getPath())) { if ((event.getAction() == ExplorerChangeEvent.ALL)) {
loadItemList(); loadItemList();
return;
}
String currentDirPath = mCurrentPageState.page.getPath();
String changedDirPath = event.getPage().getPath();
ExplorerItem item = event.getItem();
String changedItemPath = item == null ? null : item.getPath();
if (currentDirPath.equals(changedItemPath) || (currentDirPath.equals(changedDirPath) &&
event.getAction() == ExplorerChangeEvent.CHILDREN_CHANGE)) {
loadItemList();
return;
}
if (currentDirPath.equals(changedDirPath)) {
int i;
switch (event.getAction()) {
case ExplorerChangeEvent.CHANGE:
i = mExplorerItemList.update(item, event.getNewItem());
if (i >= 0) {
mExplorerAdapter.notifyItemChanged(item, i);
}
break;
case ExplorerChangeEvent.CREATE:
mExplorerItemList.insertAtFront(event.getNewItem());
mExplorerAdapter.notifyItemInserted(event.getNewItem(), 0);
break;
case ExplorerChangeEvent.REMOVE:
i = mExplorerItemList.remove(item);
if (i >= 0) {
mExplorerAdapter.notifyItemRemoved(item, i);
}
break;
}
} }
} }
@@ -417,6 +449,25 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR
} }
} }
int getItemPosition(ExplorerItem item, int i) {
if (item instanceof ExplorerPage) {
return i + positionOfCategoryDir + 1;
}
return i + positionOfCategoryFile() + 1;
}
public void notifyItemChanged(ExplorerItem item, int i) {
notifyItemChanged(getItemPosition(item, i));
}
public void notifyItemRemoved(ExplorerItem item, int i) {
notifyItemRemoved(getItemPosition(item, i));
}
public void notifyItemInserted(ExplorerItem item, int i) {
notifyItemInserted(getItemPosition(item, i));
}
@Override @Override
public int getItemCount() { public int getItemCount() {
int count = 0; int count = 0;

View File

@@ -71,7 +71,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
onFinish(execution); onFinish(execution);
} }

View File

@@ -2,6 +2,7 @@ package org.autojs.autojs.ui.viewmodel;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import org.autojs.autojs.model.explorer.ExplorerDirPage;
import org.autojs.autojs.model.explorer.ExplorerItem; import org.autojs.autojs.model.explorer.ExplorerItem;
import org.autojs.autojs.model.explorer.ExplorerPage; import org.autojs.autojs.model.explorer.ExplorerPage;
import org.autojs.autojs.model.explorer.ExplorerSorter; import org.autojs.autojs.model.explorer.ExplorerSorter;
@@ -145,6 +146,47 @@ public class ExplorerItemList {
} }
} }
public void insertAtFront(ExplorerItem item) {
if (item instanceof ExplorerPage) {
mItemGroups.add(0, (ExplorerPage) item);
} else {
mItems.add(0, item);
}
}
public int remove(ExplorerItem item) {
if (item instanceof ExplorerPage) {
return remove(mItemGroups, item);
} else {
return remove(mItems, item);
}
}
public int update(ExplorerItem oldItem, ExplorerItem newItem) {
if (oldItem instanceof ExplorerPage) {
return update(mItemGroups, (ExplorerPage) oldItem, (ExplorerPage) newItem);
} else {
return update(mItems, oldItem, newItem);
}
}
private <T> int update(ArrayList<T> list, T oldItem, T newItem) {
int i = list.indexOf(oldItem);
if (i >= 0) {
list.set(i, newItem);
}
return i;
}
private <T> int remove(ArrayList<?> list, T o) {
int i = list.indexOf(o);
if (i >= 0) {
list.remove(i);
}
return i;
}
public ExplorerPage getItemGroup(int i) { public ExplorerPage getItemGroup(int i) {
return mItemGroups.get(i); return mItemGroups.get(i);
} }

View File

@@ -57,7 +57,7 @@ runtime.init();
(function(scope){ (function(scope){
var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui', var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui',
"images", "timers", "threads", "events", "engines", "RootAutomator", "http", "storages", "floaty", "images", "timers", "threads", "events", "engines", "RootAutomator", "http", "storages", "floaty",
"sensors", "media"]; "sensors", "media", "plugins"];
var len = modules.length; var len = modules.length;
for(var i = 0; i < len; i++) { for(var i = 0; i < len; i++) {
var m = modules[i]; var m = modules[i];

View File

@@ -0,0 +1,12 @@
module.exports = function (runtime, scope) {
function plugins(){
}
plugins.load = function(packageName){
var plugin = runtime.plugins.load(packageName);
var index = require(plugin.mainScriptPath);
return index(plugin.unwrap());
}
return plugins;
}

View File

@@ -84,9 +84,12 @@ public abstract class AutoJs {
protected void init() { protected void init() {
addAccessibilityServiceDelegates(); addAccessibilityServiceDelegates();
registerActivityLifecycleCallbacks(); registerActivityLifecycleCallbacks();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_13, mContext, new BaseLoaderCallback(mContext) { try {
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_13, mContext, new BaseLoaderCallback(mContext) {
}); });
} catch (Exception e) {
e.printStackTrace();
}
} }
public abstract void ensureAccessibilityServiceEnabled(); public abstract void ensureAccessibilityServiceEnabled();

View File

@@ -67,7 +67,7 @@ public class ScriptEngineService {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
e.printStackTrace(); e.printStackTrace();
onFinish(execution); onFinish(execution);
String message = null; String message = null;
@@ -80,7 +80,7 @@ public class ScriptEngineService {
} }
if (execution.getEngine() instanceof JavaScriptEngine) { if (execution.getEngine() instanceof JavaScriptEngine) {
JavaScriptEngine engine = (JavaScriptEngine) execution.getEngine(); JavaScriptEngine engine = (JavaScriptEngine) execution.getEngine();
Exception uncaughtException = engine.getUncaughtException(); Throwable uncaughtException = engine.getUncaughtException();
if (uncaughtException != null) { if (uncaughtException != null) {
engine.getRuntime().console.error(uncaughtException); engine.getRuntime().console.error(uncaughtException);
message = uncaughtException.getMessage(); message = uncaughtException.getMessage();

View File

@@ -57,6 +57,7 @@ public class ColorFinder {
return new Point[0]; return new Point[0];
} }
Point[] points = matOfPoint.toArray(); Point[] points = matOfPoint.toArray();
OpenCVHelper.release(matOfPoint);
if (rect != null) { if (rect != null) {
for (int i = 0; i < points.length; i++) { for (int i = 0; i < points.length; i++) {
points[i].x = mScreenMetrics.scaleX((int) (points[i].x + rect.x)); points[i].x = mScreenMetrics.scaleX((int) (points[i].x + rect.x));

View File

@@ -35,6 +35,7 @@ public class OpenCVHelper {
callback.onInitFinish(); callback.onInitFinish();
return; return;
} }
mInitialized = true; mInitialized = true;
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_13, activity.getApplicationContext(), new LoaderCallback(activity) { OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_13, activity.getApplicationContext(), new LoaderCallback(activity) {

View File

@@ -0,0 +1,93 @@
package com.stardust.autojs.core.plugin;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import com.stardust.autojs.rhino.TopLevelScope;
import com.stardust.autojs.runtime.ScriptRuntime;
import java.lang.reflect.Method;
public class Plugin {
public static class PluginLoadException extends RuntimeException {
public PluginLoadException(Throwable cause) {
super(cause);
}
public PluginLoadException(String message) {
super(message);
}
}
private static final String KEY_REGISTRY = "org.autojs.plugin.sdk.registry";
public static Plugin load(Context context, Context packageContext, ScriptRuntime runtime, TopLevelScope scope) {
try {
ApplicationInfo applicationInfo = packageContext.getPackageManager().getApplicationInfo(packageContext.getPackageName(), PackageManager.GET_META_DATA);
String registryClass = applicationInfo.metaData.getString(KEY_REGISTRY);
if (registryClass == null) {
throw new PluginLoadException("no registry in metadata");
}
Class<?> pluginClass = Class.forName(registryClass, true, packageContext.getClassLoader());
Method loadDefault = pluginClass.getMethod("loadDefault", Context.class, Context.class, Object.class, Object.class);
return Plugin.create(loadDefault.invoke(null, context, packageContext, runtime, scope));
} catch (PackageManager.NameNotFoundException e) {
return null;
} catch (Throwable e) {
e.printStackTrace();
throw new PluginLoadException(e);
}
}
private static Plugin create(Object pluginInstance) {
if (pluginInstance == null)
return null;
return new Plugin(pluginInstance);
}
private final Object mPluginInstance;
private Method mGetVersion;
private Method mGetScriptDir;
private String mMainScriptPath;
public Plugin(Object pluginInstance) {
mPluginInstance = pluginInstance;
findMethods(pluginInstance.getClass());
}
@SuppressWarnings("unchecked")
private void findMethods(Class pluginClass) {
try {
mGetVersion = pluginClass.getMethod("getVersion");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
mGetScriptDir = pluginClass.getMethod("getAssetsScriptDir");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public Object unwrap() {
return mPluginInstance;
}
public String getMainScriptPath() {
return mMainScriptPath;
}
public void setMainScriptPath(String mainScriptPath) {
mMainScriptPath = mainScriptPath;
}
public String getAssetsScriptDir() {
try {
return (String) mGetScriptDir.invoke(mPluginInstance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -8,6 +8,7 @@ import com.stardust.autojs.core.ui.ViewExtras;
import com.stardust.autojs.rhino.NativeArrayLikeJavaObject; import com.stardust.autojs.rhino.NativeArrayLikeJavaObject;
import com.stardust.autojs.rhino.RhinoAndroidHelper; import com.stardust.autojs.rhino.RhinoAndroidHelper;
import com.stardust.autojs.rhino.TopLevelScope; import com.stardust.autojs.rhino.TopLevelScope;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.script.JavaScriptSource; import com.stardust.autojs.script.JavaScriptSource;
import com.stardust.autojs.script.StringScriptSource; import com.stardust.autojs.script.StringScriptSource;
import com.stardust.automator.UiObject; import com.stardust.automator.UiObject;
@@ -60,6 +61,12 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine {
ScriptableObject.putProperty(mScriptable, name, Context.javaToJS(value, mScriptable)); ScriptableObject.putProperty(mScriptable, name, Context.javaToJS(value, mScriptable));
} }
@Override
public void setRuntime(ScriptRuntime runtime) {
super.setRuntime(runtime);
runtime.setTopLevelScope(mScriptable);
}
@Override @Override
public Object doExecution(JavaScriptSource source) { public Object doExecution(JavaScriptSource source) {
Reader reader = source.getNonNullScriptReader(); Reader reader = source.getNonNullScriptReader();

View File

@@ -44,9 +44,9 @@ public interface ScriptEngine<S extends ScriptSource> {
String cwd(); String cwd();
void uncaughtException(Exception throwable); void uncaughtException(Throwable throwable);
Exception getUncaughtException(); Throwable getUncaughtException();
void setId(int id); void setId(int id);
@@ -72,7 +72,7 @@ public interface ScriptEngine<S extends ScriptSource> {
private Map<String, Object> mTags = new HashMap<>(); private Map<String, Object> mTags = new HashMap<>();
private OnDestroyListener mOnDestroyListener; private OnDestroyListener mOnDestroyListener;
private boolean mDestroyed = false; private boolean mDestroyed = false;
private Exception mUncaughtException; private Throwable mUncaughtException;
private volatile AtomicInteger mId = new AtomicInteger(ScriptExecution.NO_ID); private volatile AtomicInteger mId = new AtomicInteger(ScriptExecution.NO_ID);
@Override @Override
@@ -114,13 +114,13 @@ public interface ScriptEngine<S extends ScriptSource> {
} }
@Override @Override
public void uncaughtException(Exception throwable) { public void uncaughtException(Throwable throwable) {
mUncaughtException = throwable; mUncaughtException = throwable;
forceStop(); forceStop();
} }
@Override @Override
public Exception getUncaughtException() { public Throwable getUncaughtException() {
return mUncaughtException; return mUncaughtException;
} }

View File

@@ -59,12 +59,12 @@ public class ScriptEngineProxy<S extends ScriptSource> implements ScriptEngine<S
} }
@Override @Override
public void uncaughtException(Exception throwable) { public void uncaughtException(Throwable throwable) {
mScriptEngine.uncaughtException(throwable); mScriptEngine.uncaughtException(throwable);
} }
@Override @Override
public Exception getUncaughtException() { public Throwable getUncaughtException() {
return mScriptEngine.getUncaughtException(); return mScriptEngine.getUncaughtException();
} }

View File

@@ -40,14 +40,14 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
try { try {
prepare(engine); prepare(engine);
Object r = doExecution(engine); Object r = doExecution(engine);
Exception uncaughtException = engine.getUncaughtException(); Throwable uncaughtException = engine.getUncaughtException();
if (uncaughtException != null) { if (uncaughtException != null) {
onException(engine, uncaughtException); onException(engine, uncaughtException);
return null; return null;
} }
getListener().onSuccess(this, r); getListener().onSuccess(this, r);
return r; return r;
} catch (Exception e) { } catch (Throwable e) {
onException(engine, e); onException(engine, e);
return null; return null;
} finally { } finally {
@@ -56,7 +56,7 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
} }
} }
protected void onException(ScriptEngine engine, Exception e) { protected void onException(ScriptEngine engine, Throwable e) {
Log.w(TAG, "onException: engine = " + engine, e); Log.w(TAG, "onException: engine = " + engine, e);
getListener().onException(this, e); getListener().onException(this, e);
} }

View File

@@ -91,7 +91,7 @@ public class ScriptExecuteActivity extends AppCompatActivity {
} }
} }
private void onException(Exception e) { private void onException(Throwable e) {
mExecutionListener.onException(mScriptExecution, e); mExecutionListener.onException(mScriptExecution, e);
super.finish(); super.finish();
} }
@@ -127,7 +127,7 @@ public class ScriptExecuteActivity extends AppCompatActivity {
super.finish(); super.finish();
return; return;
} }
Exception exception = mScriptEngine.getUncaughtException(); Throwable exception = mScriptEngine.getUncaughtException();
if (exception != null) { if (exception != null) {
onException(exception); onException(exception);
} else { } else {

View File

@@ -12,5 +12,5 @@ public interface ScriptExecutionListener extends Serializable {
void onSuccess(ScriptExecution execution, Object result); void onSuccess(ScriptExecution execution, Object result);
void onException(ScriptExecution execution, Exception e); void onException(ScriptExecution execution, Throwable e);
} }

View File

@@ -24,7 +24,7 @@ public class ScriptExecutionObserver implements ScriptExecutionListener {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
for (ScriptExecutionListener listener : mScriptExecutionListeners) { for (ScriptExecutionListener listener : mScriptExecutionListeners) {
listener.onException(execution, e); listener.onException(execution, e);
} }
@@ -61,7 +61,7 @@ public class ScriptExecutionObserver implements ScriptExecutionListener {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
mScriptExecutionListener.onException(execution, e); mScriptExecutionListener.onException(execution, e);
mScriptExecutionObserver.onException(execution, e); mScriptExecutionObserver.onException(execution, e);
} }

View File

@@ -17,7 +17,7 @@ public class SimpleScriptExecutionListener implements ScriptExecutionListener {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
} }
} }

View File

@@ -16,6 +16,7 @@ import com.stardust.autojs.core.image.Colors;
import com.stardust.autojs.core.permission.PermissionRequestProxyActivity; import com.stardust.autojs.core.permission.PermissionRequestProxyActivity;
import com.stardust.autojs.core.permission.Permissions; import com.stardust.autojs.core.permission.Permissions;
import com.stardust.autojs.rhino.AndroidClassLoader; import com.stardust.autojs.rhino.AndroidClassLoader;
import com.stardust.autojs.rhino.TopLevelScope;
import com.stardust.autojs.runtime.api.AbstractShell; import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.api.AppUtils; import com.stardust.autojs.runtime.api.AppUtils;
import com.stardust.autojs.runtime.api.Console; import com.stardust.autojs.runtime.api.Console;
@@ -26,6 +27,7 @@ import com.stardust.autojs.runtime.api.Files;
import com.stardust.autojs.runtime.api.Floaty; import com.stardust.autojs.runtime.api.Floaty;
import com.stardust.autojs.core.looper.Loopers; import com.stardust.autojs.core.looper.Loopers;
import com.stardust.autojs.runtime.api.Media; import com.stardust.autojs.runtime.api.Media;
import com.stardust.autojs.runtime.api.Plugins;
import com.stardust.autojs.runtime.api.Sensors; import com.stardust.autojs.runtime.api.Sensors;
import com.stardust.autojs.runtime.api.Threads; import com.stardust.autojs.runtime.api.Threads;
import com.stardust.autojs.runtime.api.Timers; import com.stardust.autojs.runtime.api.Timers;
@@ -193,6 +195,9 @@ public class ScriptRuntime {
@ScriptVariable @ScriptVariable
public final Media media; public final Media media;
@ScriptVariable
public final Plugins plugins;
private Images images; private Images images;
private static WeakReference<Context> applicationContext; private static WeakReference<Context> applicationContext;
@@ -201,6 +206,7 @@ public class ScriptRuntime {
private Supplier<AbstractShell> mShellSupplier; private Supplier<AbstractShell> mShellSupplier;
private ScreenMetrics mScreenMetrics = new ScreenMetrics(); private ScreenMetrics mScreenMetrics = new ScreenMetrics();
private Thread mThread; private Thread mThread;
private TopLevelScope mTopLevelScope;
protected ScriptRuntime(Builder builder) { protected ScriptRuntime(Builder builder) {
@@ -223,6 +229,7 @@ public class ScriptRuntime {
floaty = new Floaty(uiHandler, ui, this); floaty = new Floaty(uiHandler, ui, this);
files = new Files(this); files = new Files(this);
media = new Media(context, this); media = new Media(context, this);
plugins = new Plugins(context, this);
} }
public void init() { public void init() {
@@ -236,6 +243,17 @@ public class ScriptRuntime {
sensors = new Sensors(uiHandler.getContext(), this); sensors = new Sensors(uiHandler.getContext(), this);
} }
public TopLevelScope getTopLevelScope() {
return mTopLevelScope;
}
public void setTopLevelScope(TopLevelScope topLevelScope) {
if (mTopLevelScope != null) {
throw new IllegalStateException("top level has already exists");
}
mTopLevelScope = topLevelScope;
}
public static void setApplicationContext(Context context) { public static void setApplicationContext(Context context) {
applicationContext = new WeakReference<>(context); applicationContext = new WeakReference<>(context);
} }
@@ -358,7 +376,7 @@ public class ScriptRuntime {
} }
} }
public void exit(Exception e) { public void exit(Throwable e) {
engines.myEngine().uncaughtException(e); engines.myEngine().uncaughtException(e);
exit(); exit();
} }
@@ -389,7 +407,7 @@ public class ScriptRuntime {
ignoresException(floaty::closeAll); ignoresException(floaty::closeAll);
try { try {
events.emit("exit"); events.emit("exit");
} catch (Exception ignored) { } catch (Throwable ignored) {
console.error("exception on exit: ", ignored); console.error("exception on exit: ", ignored);
} }
ignoresException(threads::shutDownAll); ignoresException(threads::shutDownAll);
@@ -412,7 +430,7 @@ public class ScriptRuntime {
private void ignoresException(Runnable r) { private void ignoresException(Runnable r) {
try { try {
r.run(); r.run();
} catch (Exception e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@@ -0,0 +1,49 @@
package com.stardust.autojs.runtime.api;
import android.content.Context;
import com.stardust.autojs.core.plugin.Plugin;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.pio.PFiles;
import java.io.File;
public class Plugins {
private final Context mContext;
private final ScriptRuntime mRuntime;
private File mPluginCacheDir;
public Plugins(Context context, ScriptRuntime runtime) {
mContext = context;
mRuntime = runtime;
mPluginCacheDir = new File(mContext.getCacheDir(), "plugin-scripts/");
}
public Plugin load(String packageName) {
try {
Context packageContext = mContext.createPackageContext(packageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
Plugin plugin = Plugin.load(mContext, packageContext, mRuntime, mRuntime.getTopLevelScope());
if (plugin == null) {
return null;
}
File scriptCacheDir = getScriptCacheDir(packageName);
PFiles.copyAssetDir(packageContext.getAssets(), plugin.getAssetsScriptDir(), scriptCacheDir.getPath(), null);
plugin.setMainScriptPath(new File(scriptCacheDir, "index.js").getPath());
return plugin;
} catch (Exception e) {
throw new Plugin.PluginLoadException(e);
}
}
private File getScriptCacheDir(String packageName) {
File dir = new File(mPluginCacheDir, packageName + "/");
dir.mkdirs();
return dir;
}
public void clear() {
PFiles.deleteRecursively(mPluginCacheDir);
}
}

View File

@@ -50,7 +50,7 @@ public class VMBridge_custom extends VMBridge_jdk15 {
try { try {
Object result = adapterWrapper.invoke(cf, target, topScope, proxy, method, args); Object result = adapterWrapper.invoke(cf, target, topScope, proxy, method, args);
return castReturnValue(method, result); return castReturnValue(method, result);
} catch (Exception e) { } catch (Throwable e) {
e.printStackTrace(); e.printStackTrace();
// notify the script thread to exit // notify the script thread to exit
com.stardust.autojs.runtime.ScriptRuntime runtime = engine.getRuntime(); com.stardust.autojs.runtime.ScriptRuntime runtime = engine.getRuntime();

View File

@@ -50,15 +50,19 @@ public class PFile extends File {
mSimplifyPath = PFiles.getSimplifiedPath(getPath()); mSimplifyPath = PFiles.getSimplifiedPath(getPath());
} }
public boolean renameTo(String newName) {
if (isDirectory()) @NonNull
return renameTo(new File(getParent(), newName)); public PFile renameTo(String newName) {
else PFile newFile = new PFile(getParent(), newName);
return renameTo(new File(getParent(), newName + "." + getExtension())); if (renameTo(newFile)) {
return newFile;
} else {
return this;
}
} }
@Nullable @NonNull
public PFile renameAndReturnNewFile(String newName) { public PFile renameWithoutExt(String newName) {
PFile newFile = isDirectory() ? new PFile(getParent(), newName) : PFile newFile = isDirectory() ? new PFile(getParent(), newName) :
new PFile(getParent(), newName + "." + getExtension()); new PFile(getParent(), newName + "." + getExtension());
if (renameTo(newFile)) { if (renameTo(newFile)) {

View File

@@ -296,9 +296,8 @@ public class PFiles {
} }
public static void copyAssetDir(Context context, String assetsDir, String toDir, String[] list) throws IOException { public static void copyAssetDir(AssetManager manager, String assetsDir, String toDir, String[] list) throws IOException {
new File(toDir).mkdirs(); new File(toDir).mkdirs();
AssetManager manager = context.getAssets();
if (list == null) { if (list == null) {
list = manager.list(assetsDir); list = manager.list(assetsDir);
} }
@@ -323,7 +322,7 @@ public class PFiles {
} }
} }
} else { } else {
copyAssetDir(context, fullAssetsPath, join(toDir, file), children); copyAssetDir(manager, fullAssetsPath, join(toDir, file), children);
} }
} }
} }

View File

@@ -13,4 +13,6 @@ public class ObjectHelper {
throw new NullPointerException(); throw new NullPointerException();
} }
} }
} }

View File

@@ -24,4 +24,17 @@ public class Objects {
public static boolean equals(Object a, Object b) { public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b)); return (a == b) || (a != null && a.equals(b));
} }
/**
* Returns the hash code of a non-{@code null} argument and 0 for
* a {@code null} argument.
*
* @param o an object
* @return the hash code of a non-{@code null} argument and 0 for
* a {@code null} argument
* @see Object#hashCode
*/
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
} }

View File

@@ -32,7 +32,7 @@ public class ScriptExecutionGlobalListener implements ScriptExecutionListener {
} }
@Override @Override
public void onException(ScriptExecution execution, Exception e) { public void onException(ScriptExecution execution, Throwable e) {
onFinish(execution); onFinish(execution);
} }

View File

@@ -90,7 +90,7 @@ public class AssetsProjectLauncher {
} }
PFiles.deleteRecursively(new File(mProjectDir)); PFiles.deleteRecursively(new File(mProjectDir));
try { try {
PFiles.copyAssetDir(mActivity, mAssetsProjectDir, mProjectDir, null); PFiles.copyAssetDir(mActivity.getAssets(), mAssetsProjectDir, mProjectDir, null);
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} }