Rename and refactor autojs to support future developing of other script language

This commit is contained in:
hyb1996 2017-05-07 23:32:53 +08:00
parent 840bb56528
commit 472bd46b87
25 changed files with 717 additions and 184 deletions

View File

@ -55,11 +55,11 @@ android {
}
dexcount {
format = "list"
includeClasses = false
includeClasses = true
includeFieldCount = true
includeTotalMethodCount = false
orderByMethodCount = false
verbose = false
includeTotalMethodCount = true
orderByMethodCount = true
verbose = true
maxTreeDepth = Integer.MAX_VALUE
teamCityIntegration = false
enableForInstantRun = false

View File

@ -7,14 +7,18 @@ import android.support.annotation.Nullable;
import com.stardust.autojs.ScriptEngineService;
import com.stardust.autojs.ScriptEngineServiceBuilder;
import com.stardust.autojs.engine.NodeJsJavaScriptEngineManager;
import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.runtime.*;
import com.stardust.automator.AccessibilityEventCommandHost;
import com.stardust.automator.simple_action.SimpleActionPerformHost;
import com.stardust.pio.PFile;
import com.stardust.pio.UncheckedIOException;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.script.StorageScriptProvider;
import com.stardust.scriptdroid.ui.console.StardustConsole;
import com.stardust.util.AssetsCache;
import com.stardust.util.Supplier;
import com.stardust.util.UiHandler;
import com.stardust.view.accessibility.AccessibilityInfoProvider;
@ -25,6 +29,8 @@ import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
import com.stardust.scriptdroid.ui.console.JraskaConsole;
import com.stardust.view.accessibility.AccessibilityServiceUtils;
import java.io.IOException;
/**
* Created by Stardust on 2017/4/2.
@ -33,6 +39,7 @@ import com.stardust.view.accessibility.AccessibilityServiceUtils;
public class AutoJs implements AccessibilityBridge {
private static AutoJs instance;
private static final String INIT_SCRIPT_PATH = "js/autojs_init.js";
public static AutoJs getInstance() {
return instance;
@ -54,8 +61,7 @@ public class AutoJs implements AccessibilityBridge {
private AutoJs(final Context context) {
mUiHandler = new UiHandler(context);
mAccessibilityInfoProvider = new AccessibilityInfoProvider(context.getPackageManager());
NodeJsJavaScriptEngineManager manager = new NodeJsJavaScriptEngineManager(context);
manager.setRequirePath(StorageScriptProvider.DEFAULT_DIRECTORY_PATH);
ScriptEngineManager manager = createScriptEngineManager(context);
mScriptEngineService = new ScriptEngineServiceBuilder()
.uiHandler(mUiHandler)
.globalConsole(new JraskaConsole())
@ -72,6 +78,17 @@ public class AutoJs implements AccessibilityBridge {
mScriptEngineService.registerGlobalScriptExecutionListener(new ScriptExecutionGlobalListener());
}
private NodeJsJavaScriptEngineManager createScriptEngineManager(Context context) {
NodeJsJavaScriptEngineManager manager = new NodeJsJavaScriptEngineManager(context);
manager.setRequirePath(StorageScriptProvider.DEFAULT_DIRECTORY_PATH);
try {
manager.setInitScript(PFile.read(context.getAssets().open(INIT_SCRIPT_PATH)));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return manager;
}
private void addAccessibilityServiceDelegates() {
AccessibilityWatchDogService.addDelegate(100, mAccessibilityInfoProvider);
AccessibilityWatchDogService.addDelegate(300, mAccessibilityActionRecorder);

View File

@ -6,10 +6,9 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.widget.Toast;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.script.PathChecker;
import com.stardust.autojs.script.FileScriptSource;
import com.stardust.autojs.script.ScriptSourceWithInit;
import com.stardust.autojs.script.SequenceScriptSource;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.autojs.script.StringScriptSource;
import com.stardust.scriptdroid.external.CommonUtils;
@ -41,7 +40,8 @@ public class RunIntentActivity extends Activity {
if (path == null && script != null) {
source = new StringScriptSource(script);
} else if (path != null && new PathChecker(this).checkAndToastError(path)) {
source = new ScriptSourceWithInit(new StringScriptSource(script), new FileScriptSource(path));
ScriptSource fileScriptSource = new FileScriptSource(path);
source = new SequenceScriptSource(fileScriptSource.getName(), new StringScriptSource(script), fileScriptSource);
}
if (source != null) {
Scripts.run(source);

View File

@ -10,7 +10,7 @@ import com.stardust.autojs.execution.SimpleScriptExecutionListener;
import com.stardust.autojs.runtime.ScriptInterruptedException;
import com.stardust.autojs.script.FileScriptSource;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.autojs.script.ScriptSourceWithInit;
import com.stardust.autojs.script.SequenceScriptSource;
import com.stardust.autojs.script.StringScriptSource;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.BuildConfig;
@ -52,8 +52,6 @@ public class Scripts {
}
};
private static final String INIT_SCRIPT_PATH = "js/autojs_init.js";
private static ScriptSource initScriptSource;
public static void openByOtherApps(String path) {
@ -87,27 +85,16 @@ public class Scripts {
}
public static ScriptExecution run(ScriptSource source) {
return AutoJs.getInstance().getScriptEngineService().execute(wrappedWithInitSource(source));
}
private static ScriptSource wrappedWithInitSource(ScriptSource source) {
return new ScriptSourceWithInit(getInitScriptSource(), source);
return AutoJs.getInstance().getScriptEngineService().execute(source);
}
public static ScriptExecution runWithBroadcastSender(ScriptSource scriptSource) {
return AutoJs.getInstance().getScriptEngineService().execute(wrappedWithInitSource(scriptSource), BROADCAST_SENDER_SCRIPT_EXECUTION_LISTENER);
return AutoJs.getInstance().getScriptEngineService().execute(scriptSource, BROADCAST_SENDER_SCRIPT_EXECUTION_LISTENER);
}
public static ScriptExecution run(Context context, Sample file) {
ScriptSource source = new StringScriptSource(file.name, AssetsCache.get(context.getAssets(), file.path));
return AutoJs.getInstance().getScriptEngineService().execute(wrappedWithInitSource(source));
return AutoJs.getInstance().getScriptEngineService().execute(source);
}
private static ScriptSource getInitScriptSource() {
if(initScriptSource == null || BuildConfig.DEBUG){
String initScript = AssetsCache.get(App.getApp().getAssets(), INIT_SCRIPT_PATH);
initScriptSource = new StringScriptSource(initScript);
}
return initScriptSource;
}
}

View File

@ -15,8 +15,8 @@ import com.stardust.autojs.ScriptEngineService;
import com.stardust.autojs.execution.ScriptExecution;
import com.stardust.autojs.execution.ScriptExecutionListener;
import com.stardust.autojs.execution.SimpleScriptExecutionListener;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.JavaScriptEngineManager;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.engine.AbstractScriptEngineManager;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
@ -29,7 +29,7 @@ import java.util.List;
* Created by Stardust on 2017/3/24.
*/
public class TaskListRecyclerView extends ThemeColorRecyclerView implements JavaScriptEngineManager.EngineLifecycleCallback {
public class TaskListRecyclerView extends ThemeColorRecyclerView implements AbstractScriptEngineManager.EngineLifecycleCallback {
private final OnClickListener mOnItemClickListenerProxy = new OnClickListener() {
@ -52,7 +52,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
};
private final List<JavaScriptEngine> mScriptEngines = new ArrayList<>();
private final List<ScriptEngine> mScriptEngines = new ArrayList<>();
private Adapter mAdapter;
private final ScriptEngineService mScriptEngineService = AutoJs.getInstance().getScriptEngineService();
private ScriptExecutionListener mScriptExecutionListener = new SimpleScriptExecutionListener() {
@ -129,7 +129,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
}
@Override
public void onEngineCreate(final JavaScriptEngine engine) {
public void onEngineCreate(final ScriptEngine engine) {
synchronized (mScriptEngines) {
post(new Runnable() {
@Override
@ -142,7 +142,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
}
@Override
public void onEngineRemove(final JavaScriptEngine engine) {
public void onEngineRemove(final ScriptEngine engine) {
post(new Runnable() {
@Override
public void run() {

View File

@ -6,7 +6,7 @@
<application
android:label="@string/app_name"
>
<activity android:name=".engine.ScriptExecuteActivity"/>
<activity android:name=".execution.ScriptExecuteActivity"/>
</application>
</manifest>

View File

@ -1,11 +1,11 @@
package com.stardust.autojs;
import android.content.Context;
import android.util.Log;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.JavaScriptEngineManager;
import com.stardust.autojs.engine.ScriptExecuteActivity;
import com.stardust.autojs.engine.AbstractScriptEngineManager;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.execution.ScriptExecuteActivity;
import com.stardust.autojs.execution.ExecutionConfig;
import com.stardust.autojs.execution.RunnableScriptExecution;
import com.stardust.autojs.execution.ScriptExecution;
@ -23,14 +23,9 @@ import com.stardust.util.UiHandler;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.microedition.khronos.opengles.GL;
import static com.stardust.autojs.runtime.ScriptInterruptedException.causedByInterrupted;
/**
@ -63,7 +58,7 @@ public class ScriptEngineService {
private final Context mContext;
private UiHandler mUiHandler;
private final Console mGlobalConsole;
private final JavaScriptEngineManager mJavaScriptEngineManager;
private final ScriptEngineManager mScriptEngineManager;
private final EngineLifecycleObserver mEngineLifecycleObserver = new EngineLifecycleObserver();
private ScriptExecutionObserver mScriptExecutionObserver = new ScriptExecutionObserver();
@ -71,9 +66,9 @@ public class ScriptEngineService {
mRuntimeSupplier = builder.mRuntimeSupplier;
mUiHandler = builder.mUiHandler;
mContext = mUiHandler.getContext();
mJavaScriptEngineManager = builder.mJavaScriptEngineManager;
mScriptEngineManager = builder.mScriptEngineManager;
mGlobalConsole = builder.mGlobalConsole;
mJavaScriptEngineManager.setEngineLifecycleCallback(mEngineLifecycleObserver);
mScriptEngineManager.setEngineLifecycleCallback(mEngineLifecycleObserver);
mScriptExecutionObserver.registerScriptExecutionListener(GLOBAL_LISTENER);
EVENT_BUS.register(this);
}
@ -82,8 +77,8 @@ public class ScriptEngineService {
return mGlobalConsole;
}
public JavaScriptEngine createScriptEngine() {
JavaScriptEngine engine = mJavaScriptEngineManager.createEngine();
public ScriptEngine createScriptEngine() {
ScriptEngine engine = mScriptEngineManager.createEngine();
return engine;
}
@ -91,11 +86,11 @@ public class ScriptEngineService {
return mRuntimeSupplier.get();
}
public void registerEngineLifecycleCallback(JavaScriptEngineManager.EngineLifecycleCallback engineLifecycleCallback) {
public void registerEngineLifecycleCallback(AbstractScriptEngineManager.EngineLifecycleCallback engineLifecycleCallback) {
mEngineLifecycleObserver.registerCallback(engineLifecycleCallback);
}
public void unregisterEngineLifecycleCallback(JavaScriptEngineManager.EngineLifecycleCallback engineLifecycleCallback) {
public void unregisterEngineLifecycleCallback(AbstractScriptEngineManager.EngineLifecycleCallback engineLifecycleCallback) {
mEngineLifecycleObserver.unregisterCallback(engineLifecycleCallback);
}
@ -154,7 +149,7 @@ public class ScriptEngineService {
}
public int stopAll() {
return mJavaScriptEngineManager.stopAll();
return mScriptEngineManager.stopAll();
}
@ -167,43 +162,43 @@ public class ScriptEngineService {
}
public String[] getGlobalFunctions() {
return mJavaScriptEngineManager.getGlobalFunctions();
return mScriptEngineManager.getGlobalFunctions();
}
public Set<JavaScriptEngine> getEngines() {
return mJavaScriptEngineManager.getEngines();
public Set<ScriptEngine> getEngines() {
return mScriptEngineManager.getEngines();
}
private static class EngineLifecycleObserver implements JavaScriptEngineManager.EngineLifecycleCallback {
private static class EngineLifecycleObserver implements AbstractScriptEngineManager.EngineLifecycleCallback {
private final Set<JavaScriptEngineManager.EngineLifecycleCallback> mEngineLifecycleCallbacks = new LinkedHashSet<>();
private final Set<AbstractScriptEngineManager.EngineLifecycleCallback> mEngineLifecycleCallbacks = new LinkedHashSet<>();
@Override
public void onEngineCreate(JavaScriptEngine engine) {
public void onEngineCreate(ScriptEngine engine) {
synchronized (mEngineLifecycleCallbacks) {
for (JavaScriptEngineManager.EngineLifecycleCallback callback : mEngineLifecycleCallbacks) {
for (AbstractScriptEngineManager.EngineLifecycleCallback callback : mEngineLifecycleCallbacks) {
callback.onEngineCreate(engine);
}
}
}
@Override
public void onEngineRemove(JavaScriptEngine engine) {
public void onEngineRemove(ScriptEngine engine) {
synchronized (mEngineLifecycleCallbacks) {
for (JavaScriptEngineManager.EngineLifecycleCallback callback : mEngineLifecycleCallbacks) {
for (AbstractScriptEngineManager.EngineLifecycleCallback callback : mEngineLifecycleCallbacks) {
callback.onEngineRemove(engine);
}
}
}
void registerCallback(JavaScriptEngineManager.EngineLifecycleCallback callback) {
void registerCallback(AbstractScriptEngineManager.EngineLifecycleCallback callback) {
synchronized (mEngineLifecycleCallbacks) {
mEngineLifecycleCallbacks.add(callback);
}
}
void unregisterCallback(JavaScriptEngineManager.EngineLifecycleCallback callback) {
void unregisterCallback(AbstractScriptEngineManager.EngineLifecycleCallback callback) {
synchronized (mEngineLifecycleCallbacks) {
mEngineLifecycleCallbacks.remove(callback);
}

View File

@ -1,8 +1,7 @@
package com.stardust.autojs;
import android.content.Context;
import com.stardust.autojs.engine.JavaScriptEngineManager;
import com.stardust.autojs.engine.AbstractScriptEngineManager;
import com.stardust.autojs.engine.ScriptEngineManager;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.runtime.api.Console;
import com.stardust.util.Supplier;
@ -15,7 +14,7 @@ import com.stardust.util.UiHandler;
public class ScriptEngineServiceBuilder {
Supplier<ScriptRuntime> mRuntimeSupplier;
JavaScriptEngineManager mJavaScriptEngineManager;
ScriptEngineManager mScriptEngineManager;
Console mGlobalConsole;
UiHandler mUiHandler;
@ -33,8 +32,8 @@ public class ScriptEngineServiceBuilder {
return this;
}
public ScriptEngineServiceBuilder engineManger(JavaScriptEngineManager manager) {
mJavaScriptEngineManager = manager;
public ScriptEngineServiceBuilder engineManger(ScriptEngineManager manager) {
mScriptEngineManager = manager;
return this;
}

View File

@ -17,37 +17,28 @@ import java.util.Set;
* Created by Stardust on 2017/1/27.
*/
public abstract class JavaScriptEngineManager {
public abstract class AbstractScriptEngineManager implements ScriptEngineManager {
public interface EngineLifecycleCallback {
void onEngineCreate(JavaScriptEngine engine);
void onEngineRemove(JavaScriptEngine engine);
}
private static final String TAG = "JavaScriptEngineManager";
private static final String TAG = "AbstractScriptEngineManager";
private Map<String, Object> mGlobalVariableMap = new HashMap<>();
private final Set<JavaScriptEngine> mEngines = new HashSet<>();
private final Set<ScriptEngine> mEngines = new HashSet<>();
private EngineLifecycleCallback mEngineLifecycleCallback;
private final ScriptSource INIT_SCRIPT;
private android.content.Context mContext;
public JavaScriptEngineManager(Context context) {
public AbstractScriptEngineManager(Context context) {
mContext = context;
INIT_SCRIPT = new StringScriptSource(readInitScript());
}
public JavaScriptEngine createEngine() {
JavaScriptEngine engine = createEngineInner();
public ScriptEngine createEngine() {
ScriptEngine engine = createEngineInner();
putProperties(engine);
addEngine(engine);
return engine;
}
private void addEngine(JavaScriptEngine engine) {
private void addEngine(ScriptEngine engine) {
synchronized (mEngines) {
mEngines.add(engine);
if (mEngineLifecycleCallback != null) {
@ -56,7 +47,7 @@ public abstract class JavaScriptEngineManager {
}
}
public void put(String varName, Object value) {
public void putGlobal(String varName, Object value) {
mGlobalVariableMap.put(varName, value);
}
@ -64,11 +55,11 @@ public abstract class JavaScriptEngineManager {
mEngineLifecycleCallback = engineLifecycleCallback;
}
public Set<JavaScriptEngine> getEngines() {
public Set<ScriptEngine> getEngines() {
return mEngines;
}
protected abstract JavaScriptEngine createEngineInner();
protected abstract ScriptEngine createEngineInner();
public abstract String[] getGlobalFunctions();
@ -76,13 +67,13 @@ public abstract class JavaScriptEngineManager {
return mContext;
}
protected void putProperties(JavaScriptEngine engine) {
protected void putProperties(ScriptEngine engine) {
for (Map.Entry<String, Object> variable : mGlobalVariableMap.entrySet()) {
engine.put(variable.getKey(), variable.getValue());
}
}
void removeEngine(JavaScriptEngine engine) {
public void removeEngine(ScriptEngine engine) {
synchronized (mEngines) {
if (mEngines.remove(engine) && mEngineLifecycleCallback != null) {
mEngineLifecycleCallback.onEngineRemove(engine);
@ -90,28 +81,11 @@ public abstract class JavaScriptEngineManager {
}
}
private String readInitScript() {
try {
return PFile.read(mContext.getAssets().open("javascript_engine_init.js"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public ScriptSource getInitScript() {
if (BuildConfig.DEBUG) {
// 调试时不缓存INIT_SCRIPT否则修改javascript_engine_init.js后不会更新
return new StringScriptSource(readInitScript());
} else {
return INIT_SCRIPT;
}
}
public int stopAll() {
synchronized (mEngines) {
int n = mEngines.size();
for (JavaScriptEngine engine : mEngines) {
for (ScriptEngine engine : mEngines) {
engine.forceStop();
}
return n;

View File

@ -6,6 +6,7 @@ import com.stardust.autojs.rhino_android.AndroidContextFactory;
import com.stardust.autojs.rhino_android.RhinoAndroidHelper;
import com.stardust.autojs.runtime.ScriptInterruptedException;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.pio.UncheckedIOException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
@ -14,7 +15,8 @@ import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import java.io.File;
import java.util.Hashtable;
import java.io.IOException;
import java.io.Reader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -22,7 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
* Created by Stardust on 2017/4/2.
*/
public class RhinoJavaScriptEngine implements JavaScriptEngine {
public class RhinoJavaScriptEngine implements ScriptEngine {
private static final String LOG_TAG = "RhinoJavaScriptEngine";
@ -48,7 +50,15 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
@Override
public Object execute(ScriptSource source) {
return mContext.evaluateString(mScriptable, source.getScript(), "<script>", 1, null);
Reader reader = source.getScriptReader();
if (reader == null) {
return mContext.evaluateString(mScriptable, source.getScript(), "<script>", 1, null);
}
try {
return mContext.evaluateReader(mScriptable, source.getScriptReader(), "<script>", 1, null);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override

View File

@ -1,9 +1,11 @@
package com.stardust.autojs.engine;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.BuildConfig;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.autojs.script.SequenceScriptSource;
import com.stardust.autojs.script.StringScriptSource;
import com.stardust.pio.PFile;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
@ -25,12 +27,13 @@ import java.util.List;
* Created by Stardust on 2017/3/1.
*/
public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
public class RhinoJavaScriptEngineManager extends AbstractScriptEngineManager {
private String[] mFunctions;
private String mRequirePath = "";
private ScriptSource mCustomInitScript;
private ScriptSource mInitScript;
public RhinoJavaScriptEngineManager(android.content.Context context) {
super(context);
@ -42,6 +45,38 @@ public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
return engine;
}
public void setInitScript(String script) {
setInitScriptSource(new StringScriptSource(script));
}
public void setInitScriptSource(ScriptSource initScriptSource) {
if (BuildConfig.DEBUG) {
mCustomInitScript = initScriptSource;
} else {
mInitScript = new SequenceScriptSource("<init>", new StringScriptSource(readInitScript()), initScriptSource);
}
}
private String readInitScript() {
try {
return PFile.read(getContext().getAssets().open("javascript_engine_init.js"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
ScriptSource getInitScript() {
if (mInitScript == null || BuildConfig.DEBUG) {
// 调试时不缓存INIT_SCRIPT否则修改javascript_engine_init.js后不会更新
if (mCustomInitScript != null) {
mInitScript = new SequenceScriptSource("<init>", new StringScriptSource(readInitScript()), mCustomInitScript);
} else {
mInitScript = new StringScriptSource(readInitScript());
}
}
return mInitScript;
}
public void setRequirePath(String requirePath) {
mRequirePath = requirePath;
}
@ -64,7 +99,7 @@ public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
}
private String[] getGlobalFunctionsInner() {
JavaScriptEngine engine = createEngine();
ScriptEngine engine = createEngine();
ScriptSource source = new StringScriptSource("this", "this");
engine.setTag("script", source);
Scriptable scriptable = (Scriptable) engine.execute(source);

View File

@ -6,15 +6,15 @@ import com.stardust.autojs.script.ScriptSource;
* Created by Stardust on 2017/4/2.
* <p>
* <p>
* A JavaScriptEngine is created by {@link JavaScriptEngineManager#createEngine()}, and then can be
* used to execute script with {@link JavaScriptEngine#execute(ScriptSource)} in the **same** thread.
* A ScriptEngine is created by {@link AbstractScriptEngineManager#createEngine()}, and then can be
* used to execute script with {@link ScriptEngine#execute(ScriptSource)} in the **same** thread.
* When the execution finish successfully, the engine should be destroy in the thread that created it.
* <p>
* If you want to stop the engine in other threads, you should call {@link JavaScriptEngine#forceStop()}.
* If you want to stop the engine in other threads, you should call {@link ScriptEngine#forceStop()}.
* It will throw a {@link com.stardust.autojs.runtime.ScriptStopException}.
*/
public interface JavaScriptEngine {
public interface ScriptEngine {
void put(String name, Object value);

View File

@ -0,0 +1,33 @@
package com.stardust.autojs.engine;
import java.util.Set;
/**
* Created by Stardust on 2017/5/7.
*/
public interface ScriptEngineManager {
interface EngineLifecycleCallback {
void onEngineCreate(ScriptEngine engine);
void onEngineRemove(ScriptEngine engine);
}
ScriptEngine createEngine();
void putGlobal(String varName, Object value);
void setEngineLifecycleCallback(EngineLifecycleCallback engineLifecycleCallback);
void removeEngine(ScriptEngine engine);
Set<ScriptEngine> getEngines();
String[] getGlobalFunctions();
int stopAll();
}

View File

@ -3,7 +3,7 @@ package com.stardust.autojs.execution;
import android.util.Log;
import com.stardust.autojs.ScriptEngineService;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.script.ScriptSource;
@ -14,7 +14,7 @@ import com.stardust.autojs.script.ScriptSource;
public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecution implements ScriptExecution, Runnable {
private static final String TAG = "RunnableScriptExecution";
private JavaScriptEngine mJavaScriptEngine;
private ScriptEngine mScriptEngine;
private ScriptRuntime mScriptRuntime;
private ScriptEngineService mScriptEngineService;
@ -25,12 +25,12 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
@Override
public void run() {
mJavaScriptEngine = mScriptEngineService.createScriptEngine();
mScriptEngine = mScriptEngineService.createScriptEngine();
mScriptRuntime = mScriptEngineService.createScriptRuntime();
execute(mScriptRuntime, mJavaScriptEngine);
execute(mScriptRuntime, mScriptEngine);
}
private void execute(ScriptRuntime runtime, JavaScriptEngine engine) {
private void execute(ScriptRuntime runtime, ScriptEngine engine) {
try {
prepare(runtime, engine);
doExecution(engine);
@ -43,7 +43,7 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
}
}
private void prepare(ScriptRuntime runtime, JavaScriptEngine engine) {
private void prepare(ScriptRuntime runtime, ScriptEngine engine) {
if ((getSource().getExecutionMode() & ScriptSource.EXECUTION_MODE_AUTO) != 0) {
runtime.ensureAccessibilityServiceEnabled();
}
@ -51,15 +51,15 @@ public class RunnableScriptExecution extends ScriptExecution.AbstractScriptExecu
engine.init();
}
private void doExecution(JavaScriptEngine engine) {
private void doExecution(ScriptEngine engine) {
engine.setTag("script", getSource());
getListener().onStart(this);
getListener().onSuccess(this, engine.execute(getSource()));
}
@Override
public JavaScriptEngine getEngine() {
return mJavaScriptEngine;
public ScriptEngine getEngine() {
return mScriptEngine;
}
@Override

View File

@ -1,4 +1,4 @@
package com.stardust.autojs.engine;
package com.stardust.autojs.execution;
import android.app.Activity;
import android.content.Context;
@ -6,9 +6,7 @@ import android.content.Intent;
import android.os.Bundle;
import com.stardust.autojs.ScriptEngineService;
import com.stardust.autojs.execution.ScriptExecution;
import com.stardust.autojs.execution.ScriptExecutionListener;
import com.stardust.autojs.execution.ScriptExecutionTask;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.script.ScriptSource;
@ -21,7 +19,7 @@ public class ScriptExecuteActivity extends Activity {
private static ActivityScriptExecution execution;
private Object mResult;
private JavaScriptEngine mJavaScriptEngine;
private ScriptEngine mScriptEngine;
private ScriptExecutionListener mExecutionListener;
private ScriptSource mScriptSource;
@ -39,7 +37,7 @@ public class ScriptExecuteActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mScriptSource = execution.getSource();
mJavaScriptEngine = execution.getEngine();
mScriptEngine = execution.getEngine();
mExecutionListener = execution.getListener();
runScript();
}
@ -55,15 +53,15 @@ public class ScriptExecuteActivity extends Activity {
}
private void doExecution() {
mJavaScriptEngine.setTag("script", mScriptSource);
mScriptEngine.setTag("script", mScriptSource);
mExecutionListener.onStart(execution);
mResult = mJavaScriptEngine.execute(mScriptSource);
mResult = mScriptEngine.execute(mScriptSource);
}
private void prepare() {
mJavaScriptEngine.put("activity", this);
mJavaScriptEngine.put("__runtime__", execution.getRuntime());
mJavaScriptEngine.init();
mScriptEngine.put("activity", this);
mScriptEngine.put("__runtime__", execution.getRuntime());
mScriptEngine.init();
}
@Override
@ -75,25 +73,25 @@ public class ScriptExecuteActivity extends Activity {
@Override
protected void onDestroy() {
super.onDestroy();
mJavaScriptEngine.put("activity", null);
mJavaScriptEngine.destroy();
mScriptEngine.put("activity", null);
mScriptEngine.destroy();
execution = null;
}
private static class ActivityScriptExecution extends ScriptExecution.AbstractScriptExecution {
private JavaScriptEngine mJavaScriptEngine;
private ScriptEngine mScriptEngine;
private ScriptRuntime mScriptRuntime;
ActivityScriptExecution(ScriptEngineService service, ScriptExecutionTask task) {
super(task);
mJavaScriptEngine = service.createScriptEngine();
mScriptEngine = service.createScriptEngine();
mScriptRuntime = service.createScriptRuntime();
}
@Override
public JavaScriptEngine getEngine() {
return mJavaScriptEngine;
public ScriptEngine getEngine() {
return mScriptEngine;
}
@Override

View File

@ -1,6 +1,6 @@
package com.stardust.autojs.execution;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.runtime.ScriptRuntime;
import com.stardust.autojs.script.ScriptSource;
@ -10,7 +10,7 @@ import com.stardust.autojs.script.ScriptSource;
public interface ScriptExecution {
JavaScriptEngine getEngine();
ScriptEngine getEngine();
ScriptRuntime getRuntime();
@ -29,7 +29,7 @@ public interface ScriptExecution {
}
@Override
public abstract JavaScriptEngine getEngine();
public abstract ScriptEngine getEngine();
@Override
public abstract ScriptRuntime getRuntime();

View File

@ -1,6 +1,6 @@
package com.stardust.autojs.runtime;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.api.AppUtils;
import com.stardust.autojs.runtime.api.Console;
@ -52,7 +52,7 @@ public abstract class AbstractScriptRuntime {
public abstract AbstractShell.Result shell(String cmd, int root);
@JavascriptInterface
public abstract UiSelector selector(JavaScriptEngine engine);
public abstract UiSelector selector(ScriptEngine engine);
@JavascriptInterface
public abstract boolean isStopped();

View File

@ -3,7 +3,7 @@ package com.stardust.autojs.runtime;
import android.os.Build;
import com.stardust.autojs.R;
import com.stardust.autojs.engine.JavaScriptEngine;
import com.stardust.autojs.engine.ScriptEngine;
import com.stardust.autojs.rhino_android.AndroidClassLoader;
import com.stardust.autojs.runtime.api.AbstractShell;
import com.stardust.autojs.runtime.api.AppUtils;
@ -72,7 +72,7 @@ public class ScriptRuntime extends AbstractScriptRuntime {
return ProcessShell.execCommand(cmd, root != 0);
}
public UiSelector selector(JavaScriptEngine engine) {
public UiSelector selector(ScriptEngine engine) {
return new UiSelector(mAccessibilityBridge);
}

View File

@ -2,8 +2,12 @@ package com.stardust.autojs.script;
import com.stardust.autojs.script.ScriptSource;
import com.stardust.pio.PFile;
import com.stardust.pio.UncheckedIOException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
/**
* Created by Stardust on 2017/4/2.
@ -35,6 +39,15 @@ public class FileScriptSource extends ScriptSource {
return mScript;
}
@Override
public Reader getScriptReader() {
try {
return new FileReader(mFile);
} catch (FileNotFoundException e) {
throw new UncheckedIOException(e);
}
}
@Override
public String toString() {
return mFile.toString();

View File

@ -1,10 +1,14 @@
package com.stardust.autojs.script;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import com.stardust.util.MapEntries;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -36,8 +40,21 @@ public abstract class ScriptSource implements Serializable {
return mName;
}
@NonNull
public abstract String getScript();
@Nullable
public abstract Reader getScriptReader();
@NonNull
public Reader getNonNullScriptReader() {
Reader reader = getScriptReader();
if (reader == null) {
return new StringReader(getScript());
}
return reader;
}
public int getExecutionMode() {
if (mExecutionMode == -1) {
mExecutionMode = parseExecutionMode(getScript());

View File

@ -1,33 +0,0 @@
package com.stardust.autojs.script;
/**
* Created by Stardust on 2017/4/2.
*/
public class ScriptSourceWithInit extends ScriptSource {
private String mScript;
private ScriptSource mMainScriptSource;
public ScriptSourceWithInit(ScriptSource initScriptSource, ScriptSource mainScriptSource) {
super(mainScriptSource.getName());
mMainScriptSource = mainScriptSource;
StringBuilder stringBuilder = new StringBuilder();
if (initScriptSource.getScript() != null)
stringBuilder.append(initScriptSource.getScript()).append("\n");
stringBuilder.append(mainScriptSource.getScript());
mScript = stringBuilder.toString();
}
@Override
public String getScript() {
return mScript;
}
@Override
public String toString() {
return mMainScriptSource.toString();
}
}

View File

@ -0,0 +1,54 @@
package com.stardust.autojs.script;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.stardust.io.ConcatReader;
import java.io.Reader;
import java.io.StringReader;
/**
* Created by Stardust on 2017/4/2.
*/
public class SequenceScriptSource extends ScriptSource {
private String mScript;
private ScriptSource mSecondScriptSource;
private ScriptSource mFirstScriptSource;
public SequenceScriptSource(String name, ScriptSource firstScriptSource, ScriptSource secondScriptSource) {
super(name);
mSecondScriptSource = secondScriptSource;
mFirstScriptSource = firstScriptSource;
}
@NonNull
@Override
public String getScript() {
concatScriptsIfNeeded();
return mScript;
}
private void concatScriptsIfNeeded() {
if (mScript != null)
return;
mScript = mFirstScriptSource.getScript() + mSecondScriptSource.getScript();
}
@Nullable
@Override
public Reader getScriptReader() {
if (mScript != null)
return new StringReader(mScript);
return new ConcatReader(mFirstScriptSource.getNonNullScriptReader(), mSecondScriptSource.getNonNullScriptReader());
}
@Override
public String toString() {
return mSecondScriptSource.toString();
}
}

View File

@ -1,6 +1,10 @@
package com.stardust.autojs.script;
import android.support.annotation.Nullable;
import java.io.Reader;
/**
* Created by Stardust on 2017/4/2.
*/
@ -24,4 +28,10 @@ public class StringScriptSource extends ScriptSource {
return mScript;
}
@Nullable
@Override
public Reader getScriptReader() {
return null;
}
}

View File

@ -1,5 +1,6 @@
package com.stardust.automator;
import android.app.UiAutomation;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
@ -89,7 +90,6 @@ public class UiObject extends AccessibilityNodeInfoCompat {
// FIXME: 2017/5/5
return null;
}
}
public UiObjectCollection find(UiGlobalSelector selector) {

View File

@ -0,0 +1,424 @@
package com.stardust.io;
/*
* Copyright (C) 2004 Stephen Ostermiller
* http://ostermiller.org/contact.pl?regarding=Java+Utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See COPYING.TXT for details.
*/
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A reader which reads sequentially from multiple sources.
* More information about this class is available from <a target="_top" href=
* "http://ostermiller.org/utils/">ostermiller.org</a>.
*
* @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
* @since ostermillerutils 1.04.00
*/
public class ConcatReader extends Reader {
/**
* Current index to readerQueue
*
* @since ostermillerutils 1.04.01
*/
private int readerQueueIndex = 0;
/**
* Queue of readers that have yet to be read from.
*
* @since ostermillerutils 1.04.01
*/
private ArrayList<Reader> readerQueue = new ArrayList<>();
/**
* A cache of the current reader from the readerQueue
* to avoid unneeded access to the queue which must
* be synchronized.
*
* @since ostermillerutils 1.04.01
*/
private Reader currentReader = null;
/**
* true iff the client may add more readers.
*
* @since ostermillerutils 1.04.01
*/
private boolean doneAddingReaders = false;
/**
* Causes the addReader method to throw IllegalStateException
* and read() methods to return -1 (end of stream)
* when there is no more available data.
* <p>
* Calling this method when this class is no longer accepting
* more readers has no effect.
*
* @since ostermillerutils 1.04.01
*/
public void lastReaderAdded() {
doneAddingReaders = true;
}
/**
* Add the given reader to the queue of readers from which to
* concatenate data.
*
* @param in Reader to add to the concatenation.
* @throws IllegalStateException if more readers can't be added because lastReaderAdded() has been called, close() has been called, or a constructor with reader parameters was used.
* @since ostermillerutils 1.04.01
*/
public void addReader(Reader in) {
synchronized (readerQueue) {
if (in == null) throw new NullPointerException();
if (closed) throw new IllegalStateException("ConcatReader has been closed");
if (doneAddingReaders)
throw new IllegalStateException("Cannot add more readers - the last reader has already been added.");
readerQueue.add(in);
}
}
/**
* Add the given reader to the queue of readers from which to
* concatenate data.
*
* @param in Reader to add to the concatenation.
* @throws IllegalStateException if more readers can't be added because lastReaderAdded() has been called, close() has been called, or a constructor with reader parameters was used.
* @throws NullPointerException the array of readers, or any of the contents is null.
* @since ostermillerutils 1.04.01
*/
public void addReaders(Reader[] in) {
for (Reader element : in) {
addReader(element);
}
}
/**
* Gets the current reader, looking at the next
* one in the list if the current one is null.
*
* @since ostermillerutils 1.04.01
*/
private Reader getCurrentReader() {
if (currentReader == null && readerQueueIndex < readerQueue.size()) {
synchronized (readerQueue) {
// reader queue index is advanced only by the nextReader()
// method. Don't do it here.
currentReader = readerQueue.get(readerQueueIndex);
}
}
return currentReader;
}
/**
* Indicate that we are done with the current reader and we should
* advance to the next reader.
*
* @since ostermillerutils 1.04.01
*/
private void advanceToNextReader() {
currentReader = null;
readerQueueIndex++;
}
/**
* True iff this the close() method has been called on this stream.
*
* @since ostermillerutils 1.04.00
*/
private boolean closed = false;
/**
* Create a new reader that can dynamically accept new sources.
* <p>
* New sources should be added using the addReader() method.
* When all sources have been added the lastReaderAdded() should
* be called so that read methods can return -1 (end of stream).
* <p>
* Adding new sources may by interleaved with read calls.
*
* @since ostermillerutils 1.04.01
*/
public ConcatReader() {
// Empty Constructor
}
/**
* Create a new reader with one source.
* <p>
* When using this constructor, more readers cannot
* be added later, and calling addReader() will
* throw an illegal state Exception.
*
* @param in reader to use as a source.
* @throws NullPointerException if in is null
* @since ostermillerutils 1.04.00
*/
public ConcatReader(Reader in) {
addReader(in);
lastReaderAdded();
}
/**
* Create a new reader with two sources.
* <p>
* When using this constructor, more readers cannot
* be added later, and calling addReader() will
* throw an illegal state Exception.
*
* @param in1 first reader to use as a source.
* @param in2 second reader to use as a source.
* @throws NullPointerException if either source is null.
* @since ostermillerutils 1.04.00
*/
public ConcatReader(Reader in1, Reader in2) {
addReader(in1);
addReader(in2);
lastReaderAdded();
}
/**
* Create a new reader with an arbitrary number of sources.
* <p>
* When using this constructor, more readers cannot
* be added later, and calling addReader() will
* throw an illegal state Exception.
*
* @param in readers to use as a sources.
* @throws NullPointerException if the input array on any element is null.
* @since ostermillerutils 1.04.00
*/
public ConcatReader(Reader[] in) {
addReaders(in);
lastReaderAdded();
}
/**
* Read a single character. This method will block until a
* character is available, an I/O error occurs, or the end of all underlying
* streams are reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @return The character read, as an integer in the range 0 to 65535 (0x00-0xffff),
* or -1 if the end of the stream has been reached
* @throws IOException - If an I/O error occurs
* @since ostermillerutils 1.04.00
*/
@Override
public int read() throws IOException {
if (closed) throw new IOException("Reader closed");
int r = -1;
while (r == -1) {
Reader in = getCurrentReader();
if (in == null) {
if (doneAddingReaders) return -1;
try {
Thread.sleep(100);
} catch (InterruptedException iox) {
throw new IOException("Interrupted");
}
} else {
r = in.read();
if (r == -1) advanceToNextReader();
}
}
return r;
}
/**
* Read characters into an array. This method will block until some input is available, an
* I/O error occurs, or the end of all underlying
* streams are reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @param cbuf - Destination buffer
* @return The number of characters read, or -1 if the end of the stream has been reached
* @throws IOException - If an I/O error occurs
* @throws NullPointerException - If the buffer is null.
* @since ostermillerutils 1.04.00
*/
@Override
public int read(char[] cbuf) throws IOException {
return read(cbuf, 0, cbuf.length);
}
/**
* Read characters into a portion of an array. This method will block until
* some input is available, an I/O error occurs, or the end of all underlying
* streams are reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @param cbuf Destination buffer
* @param off Offset at which to start storing characters
* @param len Maximum number of characters to read
* @return The number of characters read, or -1 if the end of the stream has been reached
* @throws IOException - If an I/O error occurs
* @throws NullPointerException - If the buffer is null.
* @throws IndexOutOfBoundsException - if length or offset are not possible.
* @since ostermillerutils 1.04.00
*/
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
if (off < 0 || len < 0 || off + len > cbuf.length) throw new IndexOutOfBoundsException();
if (closed) throw new IOException("Reader closed");
int r = -1;
while (r == -1) {
Reader in = getCurrentReader();
if (in == null) {
if (doneAddingReaders) return -1;
try {
Thread.sleep(100);
} catch (InterruptedException iox) {
throw new IOException("Interrupted");
}
} else {
r = in.read(cbuf, off, len);
if (r == -1) advanceToNextReader();
}
}
return r;
}
/**
* Skip characters. This method will block until some characters are
* available, an I/O error occurs, or the end of the stream is reached.
* <p>
* If this class in not done accepting readers and the end of the last known
* stream is reached, this method will block forever unless another thread
* adds a reader or interrupts.
*
* @param n the number of characters to skip
* @return The number of characters actually skipped
* @throws IllegalArgumentException If n is negative.
* @throws IOException If an I/O error occurs
* @since ostermillerutils 1.04.00
*/
@Override
public long skip(long n) throws IOException {
if (closed) throw new IOException("Reader closed");
if (n <= 0) return 0;
long s = -1;
while (s <= 0) {
Reader in = getCurrentReader();
if (in == null) {
if (doneAddingReaders) return 0;
try {
Thread.sleep(100);
} catch (InterruptedException iox) {
throw new IOException("Interrupted");
}
} else {
s = in.skip(n);
// When nothing was skipped it is a bit of a puzzle.
// The most common cause is that the end of the underlying
// stream was reached. In which case calling skip on it
// will always return zero. If somebody were calling skip
// until it skipped everything they needed, there would
// be an infinite loop if we were to return zero here.
// If we get zero, let us try to read one character so
// we can see if we are at the end of the stream. If so,
// we will move to the next.
if (s <= 0) {
// read() will advance to the next stream for us, so don't do it again
s = ((read() == -1) ? -1 : 1);
}
}
}
return s;
}
/**
* Tell whether this stream is ready to be read.
*
* @return True if the next read() is guaranteed not to block for input,
* false otherwise. Note that returning false does not guarantee that the next
* read will block.
* @throws IOException If an I/O error occurs
* @since ostermillerutils 1.04.00
*/
@Override
public boolean ready() throws IOException {
if (closed) throw new IOException("Reader closed");
Reader in = getCurrentReader();
if (in == null) return false;
return in.ready();
}
/**
* Close the stream and any underlying streams.
* Once a stream has been closed, further read(), ready(), mark(), or reset()
* invocations will throw an IOException. Closing a previously-closed stream,
* however, has no effect.
*
* @throws IOException If an I/O error occurs
* @since ostermillerutils 1.04.00
*/
@Override
public void close() throws IOException {
if (closed) return;
for (Reader reader : readerQueue) {
reader.close();
}
closed = true;
}
/**
* Mark not supported.
*
* @throws IOException because mark is not supported.
* @since ostermillerutils 1.04.00
*/
@Override
public void mark(int readlimit) throws IOException {
throw new IOException("Mark not supported");
}
/**
* Reset not supported.
*
* @throws IOException because reset is not supported.
* @since ostermillerutils 1.04.00
*/
@Override
public void reset() throws IOException {
throw new IOException("Reset not supported");
}
/**
* Mark not supported.
*
* @return false
* @since ostermillerutils 1.04.00
*/
@Override
public boolean markSupported() {
return false;
}
}