diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index fb16afc1..0c642a68 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/src/main/assets/sample/界面控件/自定义控件-带颜色按钮.js b/app/src/main/assets/sample/界面控件/自定义控件-带颜色按钮.js index 3a7b5167..a53b1921 100644 --- a/app/src/main/assets/sample/界面控件/自定义控件-带颜色按钮.js +++ b/app/src/main/assets/sample/界面控件/自定义控件-带颜色按钮.js @@ -1,7 +1,7 @@ "ui"; var ColoredButton = (function() { - //继承至ui.Widget + //继承ui.Widget util.extend(ColoredButton, ui.Widget); function ColoredButton() { diff --git a/app/src/main/java/org/autojs/autojs/autojs/ScriptExecutionGlobalListener.java b/app/src/main/java/org/autojs/autojs/autojs/ScriptExecutionGlobalListener.java index 90e58dfd..bdd62629 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/ScriptExecutionGlobalListener.java +++ b/app/src/main/java/org/autojs/autojs/autojs/ScriptExecutionGlobalListener.java @@ -34,7 +34,7 @@ public class ScriptExecutionGlobalListener implements ScriptExecutionListener { } @Override - public void onException(ScriptExecution execution, Exception e) { + public void onException(ScriptExecution execution, Throwable e) { onFinish(execution); } diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java b/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java index cb8a5e39..bf4e83b6 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/Explorer.java @@ -87,14 +87,14 @@ public class Explorer { if (cachedParent != null) { cachedParent.addChild(item); } - mEventBus.post(new ExplorerChangeEvent(parent, CREATE, item)); + mEventBus.post(new ExplorerChangeEvent(parent, CREATE, item, item)); } @SuppressWarnings("unchecked") public void refreshAll() { if (mExplorerPageLruCache != null) mExplorerPageLruCache.evictAll(); - mEventBus.post(new ExplorerChangeEvent(ALL)); + mEventBus.post(ExplorerChangeEvent.EVENT_ALL); } diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerChangeEvent.java b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerChangeEvent.java index 825f9854..aac0b9b8 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerChangeEvent.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerChangeEvent.java @@ -1,13 +1,18 @@ package org.autojs.autojs.model.explorer; +import com.stardust.util.ObjectHelper; + public class ExplorerChangeEvent { + public static final int REMOVE = 0; public static final int CREATE = 1; public static final int CHANGE = 2; public static final int ALL = 3; public static final int CHILDREN_CHANGE = 4; + public static final ExplorerChangeEvent EVENT_ALL = new ExplorerChangeEvent(ALL); + private final int mAction; private final ExplorerItem mItem; private final ExplorerItem mNewItem; @@ -21,10 +26,10 @@ public class ExplorerChangeEvent { } 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); } @@ -43,4 +48,30 @@ public class ExplorerChangeEvent { public ExplorerPage getPage() { 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); + } } diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerDirPage.java b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerDirPage.java index 55c0e552..c0480893 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerDirPage.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerDirPage.java @@ -44,7 +44,7 @@ public class ExplorerDirPage extends ExplorerFileItem implements ExplorerPage { @Override public ExplorerFileItem rename(String newName) { - return new ExplorerDirPage(getFile().renameAndReturnNewFile(newName), getParent()); + return new ExplorerDirPage(getFile().renameTo(newName), getParent()); } protected int indexOf(ExplorerItem child){ diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerFileItem.java b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerFileItem.java index 73fbf984..e042bc1b 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerFileItem.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerFileItem.java @@ -2,6 +2,7 @@ package org.autojs.autojs.model.explorer; import com.stardust.pio.PFile; import com.stardust.util.ObjectHelper; +import com.stardust.util.Objects; import org.autojs.autojs.model.script.ScriptFile; @@ -71,7 +72,7 @@ public class ExplorerFileItem implements ExplorerItem { } public ExplorerFileItem rename(String newName) { - return new ExplorerFileItem(mFile.renameAndReturnNewFile(newName), getParent()); + return new ExplorerFileItem(mFile.renameTo(newName), getParent()); } @Override @@ -102,4 +103,24 @@ public class ExplorerFileItem implements ExplorerItem { String type = getType(); 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); + } } + diff --git a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerProjectPage.java b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerProjectPage.java index 0a56322e..9710d7a3 100644 --- a/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerProjectPage.java +++ b/app/src/main/java/org/autojs/autojs/model/explorer/ExplorerProjectPage.java @@ -30,6 +30,6 @@ public class ExplorerProjectPage extends ExplorerDirPage { @Override public ExplorerFileItem rename(String newName) { - return new ExplorerProjectPage(getFile().renameAndReturnNewFile(newName), getParent(), mProjectConfig); + return new ExplorerProjectPage(getFile().renameTo(newName), getParent(), mProjectConfig); } } diff --git a/app/src/main/java/org/autojs/autojs/model/script/Scripts.java b/app/src/main/java/org/autojs/autojs/model/script/Scripts.java index 557bf79f..e5fd0de9 100644 --- a/app/src/main/java/org/autojs/autojs/model/script/Scripts.java +++ b/app/src/main/java/org/autojs/autojs/model/script/Scripts.java @@ -52,7 +52,7 @@ public class Scripts { } @Override - public void onException(ScriptExecution execution, Exception e) { + public void onException(ScriptExecution execution, Throwable e) { RhinoException rhinoException = getRhinoException(e); int line = -1, col = 0; if (rhinoException != null) { diff --git a/app/src/main/java/org/autojs/autojs/ui/common/FileNameInputDialog.java b/app/src/main/java/org/autojs/autojs/ui/common/FileNameInputDialog.java new file mode 100644 index 00000000..f8dd7c71 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/common/FileNameInputDialog.java @@ -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); + } +} diff --git a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java index 87bc1a40..267f67c1 100644 --- a/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java +++ b/app/src/main/java/org/autojs/autojs/ui/common/ScriptOperations.java @@ -269,10 +269,8 @@ public class ScriptOperations { } public Observable rename(final ExplorerFileItem item) { - final ScriptFile oldFile = new ScriptFile(item.getPath()); String originalName = item.getName(); - return showNameInputDialog(originalName, new InputCallback(oldFile.isDirectory() ? null : PFiles.getExtension(item.getName()), - originalName)) + return showNameInputDialog(originalName, new InputCallback(null, originalName)) .map(newName -> { ExplorerFileItem newItem = item.rename(newName); if (ObjectHelper.equals(newItem.toScriptFile(), item.toScriptFile())) { @@ -307,18 +305,23 @@ public class ScriptOperations { @SuppressLint("CheckResult") public void deleteWithoutConfirm(final ScriptFile scriptFile) { + boolean isDir = scriptFile.isDirectory(); Observable.fromPublisher((Publisher) s -> s.onNext(PFiles.deleteRecursively(scriptFile))) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(deleted -> { showMessage(deleted ? R.string.text_already_delete : R.string.text_delete_failed); if (deleted) - notifyFileRemoved(mCurrentDirectory, scriptFile); + notifyFileRemoved(isDir, scriptFile); }); } - private void notifyFileRemoved(ScriptFile directory, ScriptFile scriptFile) { - mExplorer.notifyItemRemoved(new ExplorerFileItem(scriptFile, mExplorerPage)); + private void notifyFileRemoved(boolean isDir, ScriptFile scriptFile) { + if (isDir) { + mExplorer.notifyItemRemoved(new ExplorerDirPage(scriptFile, mExplorerPage)); + } else { + mExplorer.notifyItemRemoved(new ExplorerFileItem(scriptFile, mExplorerPage)); + } } diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java index 20af1c05..b7c183d6 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java @@ -10,6 +10,7 @@ import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; +import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -243,9 +244,40 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR @Subscribe public void onExplorerChange(ExplorerChangeEvent event) { - if ((event.getAction() == ExplorerChangeEvent.ALL) - || mCurrentPageState.page.getPath().equals(event.getPage().getPath())) { + Log.d(LOG_TAG, "on explorer change: " + event); + if ((event.getAction() == ExplorerChangeEvent.ALL)) { 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 public int getItemCount() { int count = 0; diff --git a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java index 3371aa46..770ff9bd 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/main/task/TaskListRecyclerView.java @@ -71,7 +71,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView { } @Override - public void onException(ScriptExecution execution, Exception e) { + public void onException(ScriptExecution execution, Throwable e) { onFinish(execution); } diff --git a/app/src/main/java/org/autojs/autojs/ui/viewmodel/ExplorerItemList.java b/app/src/main/java/org/autojs/autojs/ui/viewmodel/ExplorerItemList.java index 5e9d4afc..c88abcbb 100644 --- a/app/src/main/java/org/autojs/autojs/ui/viewmodel/ExplorerItemList.java +++ b/app/src/main/java/org/autojs/autojs/ui/viewmodel/ExplorerItemList.java @@ -2,6 +2,7 @@ package org.autojs.autojs.ui.viewmodel; import android.content.SharedPreferences; +import org.autojs.autojs.model.explorer.ExplorerDirPage; import org.autojs.autojs.model.explorer.ExplorerItem; import org.autojs.autojs.model.explorer.ExplorerPage; 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 int update(ArrayList list, T oldItem, T newItem) { + int i = list.indexOf(oldItem); + if (i >= 0) { + list.set(i, newItem); + } + return i; + } + + private int remove(ArrayList list, T o) { + int i = list.indexOf(o); + if (i >= 0) { + list.remove(i); + } + return i; + } + public ExplorerPage getItemGroup(int i) { return mItemGroups.get(i); } diff --git a/autojs/src/main/assets/init.js b/autojs/src/main/assets/init.js index 0945ee00..74814858 100644 --- a/autojs/src/main/assets/init.js +++ b/autojs/src/main/assets/init.js @@ -57,7 +57,7 @@ runtime.init(); (function(scope){ var modules = ['app', 'automator', 'console', 'dialogs', 'io', 'selector', 'shell', 'web', 'ui', "images", "timers", "threads", "events", "engines", "RootAutomator", "http", "storages", "floaty", - "sensors", "media"]; + "sensors", "media", "plugins"]; var len = modules.length; for(var i = 0; i < len; i++) { var m = modules[i]; diff --git a/autojs/src/main/assets/modules/__plugins__.js b/autojs/src/main/assets/modules/__plugins__.js new file mode 100644 index 00000000..fac1aab2 --- /dev/null +++ b/autojs/src/main/assets/modules/__plugins__.js @@ -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; +} \ No newline at end of file diff --git a/autojs/src/main/java/com/stardust/autojs/AutoJs.java b/autojs/src/main/java/com/stardust/autojs/AutoJs.java index 25a75dc1..7aa45048 100644 --- a/autojs/src/main/java/com/stardust/autojs/AutoJs.java +++ b/autojs/src/main/java/com/stardust/autojs/AutoJs.java @@ -84,9 +84,12 @@ public abstract class AutoJs { protected void init() { addAccessibilityServiceDelegates(); 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(); diff --git a/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java b/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java index ddba7aaf..19d0976e 100644 --- a/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java +++ b/autojs/src/main/java/com/stardust/autojs/ScriptEngineService.java @@ -67,7 +67,7 @@ public class ScriptEngineService { } @Override - public void onException(ScriptExecution execution, Exception e) { + public void onException(ScriptExecution execution, Throwable e) { e.printStackTrace(); onFinish(execution); String message = null; @@ -80,7 +80,7 @@ public class ScriptEngineService { } if (execution.getEngine() instanceof JavaScriptEngine) { JavaScriptEngine engine = (JavaScriptEngine) execution.getEngine(); - Exception uncaughtException = engine.getUncaughtException(); + Throwable uncaughtException = engine.getUncaughtException(); if (uncaughtException != null) { engine.getRuntime().console.error(uncaughtException); message = uncaughtException.getMessage(); diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java b/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java index 38eb8f6d..eb1deb33 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java @@ -57,6 +57,7 @@ public class ColorFinder { return new Point[0]; } Point[] points = matOfPoint.toArray(); + OpenCVHelper.release(matOfPoint); if (rect != null) { for (int i = 0; i < points.length; i++) { points[i].x = mScreenMetrics.scaleX((int) (points[i].x + rect.x)); diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/OpenCVHelper.java b/autojs/src/main/java/com/stardust/autojs/core/image/OpenCVHelper.java index c1f5d725..d2c97ca3 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/OpenCVHelper.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/OpenCVHelper.java @@ -35,6 +35,7 @@ public class OpenCVHelper { callback.onInitFinish(); return; } + mInitialized = true; OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_13, activity.getApplicationContext(), new LoaderCallback(activity) { diff --git a/autojs/src/main/java/com/stardust/autojs/core/plugin/Plugin.java b/autojs/src/main/java/com/stardust/autojs/core/plugin/Plugin.java new file mode 100644 index 00000000..373ce64d --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/core/plugin/Plugin.java @@ -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); + } + } +} diff --git a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java index 8009a8d9..08bafe06 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/RhinoJavaScriptEngine.java @@ -8,6 +8,7 @@ import com.stardust.autojs.core.ui.ViewExtras; import com.stardust.autojs.rhino.NativeArrayLikeJavaObject; import com.stardust.autojs.rhino.RhinoAndroidHelper; import com.stardust.autojs.rhino.TopLevelScope; +import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.autojs.script.JavaScriptSource; import com.stardust.autojs.script.StringScriptSource; import com.stardust.automator.UiObject; @@ -60,6 +61,12 @@ public class RhinoJavaScriptEngine extends JavaScriptEngine { ScriptableObject.putProperty(mScriptable, name, Context.javaToJS(value, mScriptable)); } + @Override + public void setRuntime(ScriptRuntime runtime) { + super.setRuntime(runtime); + runtime.setTopLevelScope(mScriptable); + } + @Override public Object doExecution(JavaScriptSource source) { Reader reader = source.getNonNullScriptReader(); diff --git a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java index dca86616..31ed06ac 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngine.java @@ -44,9 +44,9 @@ public interface ScriptEngine { String cwd(); - void uncaughtException(Exception throwable); + void uncaughtException(Throwable throwable); - Exception getUncaughtException(); + Throwable getUncaughtException(); void setId(int id); @@ -72,7 +72,7 @@ public interface ScriptEngine { private Map mTags = new HashMap<>(); private OnDestroyListener mOnDestroyListener; private boolean mDestroyed = false; - private Exception mUncaughtException; + private Throwable mUncaughtException; private volatile AtomicInteger mId = new AtomicInteger(ScriptExecution.NO_ID); @Override @@ -114,13 +114,13 @@ public interface ScriptEngine { } @Override - public void uncaughtException(Exception throwable) { + public void uncaughtException(Throwable throwable) { mUncaughtException = throwable; forceStop(); } @Override - public Exception getUncaughtException() { + public Throwable getUncaughtException() { return mUncaughtException; } diff --git a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java index 298b2323..889774d3 100644 --- a/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java +++ b/autojs/src/main/java/com/stardust/autojs/engine/ScriptEngineProxy.java @@ -59,12 +59,12 @@ public class ScriptEngineProxy implements ScriptEngine(context); } @@ -358,7 +376,7 @@ public class ScriptRuntime { } } - public void exit(Exception e) { + public void exit(Throwable e) { engines.myEngine().uncaughtException(e); exit(); } @@ -389,7 +407,7 @@ public class ScriptRuntime { ignoresException(floaty::closeAll); try { events.emit("exit"); - } catch (Exception ignored) { + } catch (Throwable ignored) { console.error("exception on exit: ", ignored); } ignoresException(threads::shutDownAll); @@ -412,7 +430,7 @@ public class ScriptRuntime { private void ignoresException(Runnable r) { try { r.run(); - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); } } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Plugins.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Plugins.java new file mode 100644 index 00000000..d0ac77ca --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Plugins.java @@ -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); + } + +} diff --git a/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java b/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java index bcd69bc0..6f1d1e7c 100644 --- a/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java +++ b/autojs/src/main/java/org/mozilla/javascript/VMBridge_custom.java @@ -50,7 +50,7 @@ public class VMBridge_custom extends VMBridge_jdk15 { try { Object result = adapterWrapper.invoke(cf, target, topScope, proxy, method, args); return castReturnValue(method, result); - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); // notify the script thread to exit com.stardust.autojs.runtime.ScriptRuntime runtime = engine.getRuntime(); diff --git a/common/src/main/java/com/stardust/pio/PFile.java b/common/src/main/java/com/stardust/pio/PFile.java index 1fca3829..38784e3f 100644 --- a/common/src/main/java/com/stardust/pio/PFile.java +++ b/common/src/main/java/com/stardust/pio/PFile.java @@ -50,15 +50,19 @@ public class PFile extends File { mSimplifyPath = PFiles.getSimplifiedPath(getPath()); } - public boolean renameTo(String newName) { - if (isDirectory()) - return renameTo(new File(getParent(), newName)); - else - return renameTo(new File(getParent(), newName + "." + getExtension())); + + @NonNull + public PFile renameTo(String newName) { + PFile newFile = new PFile(getParent(), newName); + if (renameTo(newFile)) { + return newFile; + } else { + return this; + } } - @Nullable - public PFile renameAndReturnNewFile(String newName) { + @NonNull + public PFile renameWithoutExt(String newName) { PFile newFile = isDirectory() ? new PFile(getParent(), newName) : new PFile(getParent(), newName + "." + getExtension()); if (renameTo(newFile)) { diff --git a/common/src/main/java/com/stardust/pio/PFiles.java b/common/src/main/java/com/stardust/pio/PFiles.java index 7ec89600..c867c24b 100644 --- a/common/src/main/java/com/stardust/pio/PFiles.java +++ b/common/src/main/java/com/stardust/pio/PFiles.java @@ -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(); - AssetManager manager = context.getAssets(); if (list == null) { list = manager.list(assetsDir); } @@ -323,7 +322,7 @@ public class PFiles { } } } else { - copyAssetDir(context, fullAssetsPath, join(toDir, file), children); + copyAssetDir(manager, fullAssetsPath, join(toDir, file), children); } } } diff --git a/common/src/main/java/com/stardust/util/ObjectHelper.java b/common/src/main/java/com/stardust/util/ObjectHelper.java index 090e6609..97384662 100644 --- a/common/src/main/java/com/stardust/util/ObjectHelper.java +++ b/common/src/main/java/com/stardust/util/ObjectHelper.java @@ -13,4 +13,6 @@ public class ObjectHelper { throw new NullPointerException(); } } + + } diff --git a/common/src/main/java/com/stardust/util/Objects.java b/common/src/main/java/com/stardust/util/Objects.java index 8af62d0f..17466d6a 100644 --- a/common/src/main/java/com/stardust/util/Objects.java +++ b/common/src/main/java/com/stardust/util/Objects.java @@ -24,4 +24,17 @@ public class Objects { public static boolean equals(Object a, Object 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; + } } diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/ScriptExecutionGlobalListener.java b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/ScriptExecutionGlobalListener.java index c503e57d..13e7d1af 100644 --- a/inrt/src/main/java/com/stardust/auojs/inrt/autojs/ScriptExecutionGlobalListener.java +++ b/inrt/src/main/java/com/stardust/auojs/inrt/autojs/ScriptExecutionGlobalListener.java @@ -32,7 +32,7 @@ public class ScriptExecutionGlobalListener implements ScriptExecutionListener { } @Override - public void onException(ScriptExecution execution, Exception e) { + public void onException(ScriptExecution execution, Throwable e) { onFinish(execution); } diff --git a/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.java b/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.java index 1ee45672..0f6aa773 100644 --- a/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.java +++ b/inrt/src/main/java/com/stardust/auojs/inrt/launch/AssetsProjectLauncher.java @@ -90,7 +90,7 @@ public class AssetsProjectLauncher { } PFiles.deleteRecursively(new File(mProjectDir)); try { - PFiles.copyAssetDir(mActivity, mAssetsProjectDir, mProjectDir, null); + PFiles.copyAssetDir(mActivity.getAssets(), mAssetsProjectDir, mProjectDir, null); } catch (IOException e) { throw new UncheckedIOException(e); }