Dying...
This commit is contained in:
@@ -75,6 +75,7 @@ dependencies {
|
||||
compile group:'com.twofortyfouram', name:'android-plugin-client-sdk-for-locale', version:'[4.0.2, 5.0['
|
||||
compile 'com.android.volley:volley:1.0.0'
|
||||
compile 'com.github.hyb1996:EnhancedFloaty:0.12'
|
||||
compile 'com.flurry.android:analytics:7.0.0@aar'
|
||||
compile 'com.android.support:multidex:1.0.1'
|
||||
compile(name: 'libtermexec-release', ext: 'aar')
|
||||
compile(name: 'emulatorview-release', ext: 'aar')
|
||||
|
||||
29
app/proguard-rules.pro
vendored
29
app/proguard-rules.pro
vendored
@@ -81,4 +81,31 @@
|
||||
}
|
||||
|
||||
-keepattributes Signature
|
||||
-keepattributes EnclosingMethod
|
||||
-keepattributes EnclosingMethod
|
||||
|
||||
|
||||
# Required to preserve the Flurry SDK
|
||||
-keep class com.flurry.** { *; }
|
||||
-dontwarn com.flurry.**
|
||||
-keepattributes *Annotation*,EnclosingMethod,Signature
|
||||
-keepclasseswithmembers class * {
|
||||
public (android.content.Context, android.util.AttributeSet, int);
|
||||
}
|
||||
|
||||
# Google Play Services library
|
||||
-keep class * extends java.util.ListResourceBundle {
|
||||
protected Object[ ][ ] getContents();
|
||||
}
|
||||
|
||||
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
|
||||
public static final *** NULL;
|
||||
}
|
||||
|
||||
-keepnames @com.google.android.gms.common.annotation.KeepName class *
|
||||
-keepclassmembernames class * {
|
||||
@com.google.android.gms.common.annotation.KeepName *;
|
||||
}
|
||||
|
||||
-keepnames class * implements android.os.Parcelable {
|
||||
public static final ** CREATOR;
|
||||
}
|
||||
@@ -3,9 +3,11 @@ package com.stardust.scriptdroid;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Keep;
|
||||
import android.support.multidex.MultiDexApplication;
|
||||
|
||||
import com.flurry.android.FlurryAgent;
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.stardust.app.SimpleActivityLifecycleCallbacks;
|
||||
import com.stardust.app.VolumeChangeObserver;
|
||||
@@ -40,10 +42,16 @@ public class App extends MultiDexApplication {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
instance = new WeakReference<>(this);
|
||||
setUpStaticsTool();
|
||||
setUpDebugEnvironment();
|
||||
init();
|
||||
registerActivityLifecycleCallback();
|
||||
}
|
||||
|
||||
private void setUpStaticsTool() {
|
||||
new FlurryAgent.Builder()
|
||||
.withLogEnabled(true)
|
||||
.build(this, "D42MH48ZN4PJC5TKNYZD");
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +88,12 @@ public class App extends MultiDexApplication {
|
||||
private void registerActivityLifecycleCallback() {
|
||||
registerActivityLifecycleCallbacks(new SimpleActivityLifecycleCallbacks() {
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
super.onActivityCreated(activity, savedInstanceState);
|
||||
FlurryAgent.logEvent(activity.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
currentActivity = null;
|
||||
|
||||
@@ -2,19 +2,24 @@ package com.stardust.scriptdroid.autojs;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.flurry.android.FlurryAgent;
|
||||
import com.stardust.autojs.ScriptEngineService;
|
||||
import com.stardust.autojs.ScriptEngineServiceBuilder;
|
||||
import com.stardust.autojs.ScriptExecutionListener;
|
||||
import com.stardust.autojs.engine.JavaScriptEngine;
|
||||
import com.stardust.autojs.engine.NodeJsJavaScriptEngineManager;
|
||||
import com.stardust.autojs.runtime.*;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.automator.simple_action.SimpleActionPerformHost;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.scripts.StorageScriptProvider;
|
||||
import com.stardust.util.Supplier;
|
||||
import com.stardust.view.accessibility.AccessibilityInfoProvider;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.scriptdroid.record.accessibility.AccessibilityActionRecorder;
|
||||
@@ -46,23 +51,49 @@ public class AutoJs implements AccessibilityBridge {
|
||||
private final LayoutInspector mLayoutInspector = new LayoutInspector();
|
||||
private final ScriptEngineService mScriptEngineService;
|
||||
private final AccessibilityInfoProvider mAccessibilityInfoProvider;
|
||||
private final ScriptRuntime mRuntime;
|
||||
private final Handler mUiHandler;
|
||||
|
||||
|
||||
private AutoJs(Context context) {
|
||||
private AutoJs(final Context context) {
|
||||
mUiHandler = new Handler(context.getMainLooper());
|
||||
mAccessibilityInfoProvider = new AccessibilityInfoProvider(context.getPackageManager());
|
||||
Console console = new TimberConsole();
|
||||
mRuntime = new ScriptRuntime(context, console, this);
|
||||
NodeJsJavaScriptEngineManager manager = new NodeJsJavaScriptEngineManager(context, mRuntime);
|
||||
NodeJsJavaScriptEngineManager manager = new NodeJsJavaScriptEngineManager(context);
|
||||
manager.setRequirePath(StorageScriptProvider.DEFAULT_DIRECTORY_PATH);
|
||||
mScriptEngineService = new ScriptEngineServiceBuilder()
|
||||
.context(context)
|
||||
.engineManger(manager)
|
||||
.console(console)
|
||||
.runtime(mRuntime)
|
||||
.runtime(new Supplier<ScriptRuntime>() {
|
||||
|
||||
@Override
|
||||
public ScriptRuntime get() {
|
||||
return new ScriptRuntime(context, mUiHandler, new TimberConsole(), AutoJs.this);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
ScriptEngineService.setInstance(mScriptEngineService);
|
||||
addAccessibilityServiceDelegates();
|
||||
setDefaultScriptExecutionListener(mScriptEngineService);
|
||||
}
|
||||
|
||||
|
||||
private static void setDefaultScriptExecutionListener(ScriptEngineService scriptEngineService) {
|
||||
final ScriptExecutionListener listener = scriptEngineService.getDefaultScriptExecutionListener();
|
||||
scriptEngineService.setDefaultScriptExecutionListener(new ScriptExecutionListener() {
|
||||
@Override
|
||||
public void onStart(JavaScriptEngine engine, ScriptSource source) {
|
||||
listener.onStart(engine, source);
|
||||
FlurryAgent.logEvent("EXEC:" + source.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(JavaScriptEngine engine, ScriptSource source, Object result) {
|
||||
listener.onSuccess(engine, source, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(JavaScriptEngine engine, ScriptSource source, Exception e) {
|
||||
listener.onException(engine, source, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addAccessibilityServiceDelegates() {
|
||||
@@ -113,7 +144,6 @@ public class AutoJs implements AccessibilityBridge {
|
||||
}
|
||||
}
|
||||
if (errorMessage != null) {
|
||||
mRuntime.toast(errorMessage);
|
||||
throw new ScriptStopException(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,11 +154,7 @@ public class HoverMenuService extends Service {
|
||||
}
|
||||
|
||||
private void captureCurrentWindow() {
|
||||
NodeInfo nodeInfo = AutoJs.getInstance().getLayoutInspector().captureCurrentWindow();
|
||||
if (nodeInfo == null)
|
||||
return;
|
||||
mFloatingLayoutHierarchyView.setRootNode(nodeInfo);
|
||||
mFloatingLayoutBoundsView.setRootNode(nodeInfo);
|
||||
AutoJs.getInstance().getLayoutInspector().captureCurrentWindow();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -216,11 +212,13 @@ public class HoverMenuService extends Service {
|
||||
}
|
||||
|
||||
private void showLayoutBounds() {
|
||||
mFloatingLayoutBoundsView.setRootNode(AutoJs.getInstance().getLayoutInspector().getCapture());
|
||||
mWindowHoverMenu.getHoverMenuView().setVisibility(View.GONE);
|
||||
showView(mFloatingLayoutBoundsView);
|
||||
}
|
||||
|
||||
public void showLayoutHierarchy() {
|
||||
mFloatingLayoutHierarchyView.setRootNode(AutoJs.getInstance().getLayoutInspector().getCapture());
|
||||
mWindowHoverMenu.getHoverMenuView().setVisibility(View.GONE);
|
||||
showView(mFloatingLayoutHierarchyView);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.external.floating_window.menu.HoverMenuService;
|
||||
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
|
||||
import com.stardust.util.ClipboardUtil;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
import com.stardust.util.MessageEvent;
|
||||
@@ -47,20 +48,31 @@ public class MainMenuNavigatorContent implements NavigatorContent {
|
||||
|
||||
@ViewBinding.Click(R.id.layout_hierarchy)
|
||||
private void showLayoutHierarchy() {
|
||||
if (AutoJs.getInstance().getLayoutInspector().getCapture() == null) {
|
||||
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_HIERARCHY));
|
||||
if (!ensureCapture()) {
|
||||
return;
|
||||
}
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_HIERARCHY));
|
||||
}
|
||||
|
||||
private boolean ensureCapture() {
|
||||
LayoutInspector inspector = AutoJs.getInstance().getLayoutInspector();
|
||||
if (inspector.isDumping()) {
|
||||
Toast.makeText(mView.getContext(), R.string.text_layout_inspector_is_dumping, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
if (inspector.getCapture() == null) {
|
||||
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.layout_bounds)
|
||||
private void showLayoutBounds() {
|
||||
if (AutoJs.getInstance().getLayoutInspector().getCapture() == null) {
|
||||
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_BOUNDS));
|
||||
if (!ensureCapture()) {
|
||||
return;
|
||||
}
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_BOUNDS));
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.stop_all_running_scripts)
|
||||
|
||||
@@ -118,7 +118,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
|
||||
private void resumeRecord() {
|
||||
mRecorder.resume();
|
||||
setState(Recorder.STATE_RECORDING);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
private void pauseRecord() {
|
||||
@@ -131,7 +131,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
|
||||
mRecorder.setOnStateChangedListener(this);
|
||||
mRecorder.start();
|
||||
setState(Recorder.STATE_RECORDING);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
private void setState(int state) {
|
||||
@@ -147,7 +147,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
|
||||
private void stopRecord() {
|
||||
mRecorder.stop();
|
||||
setState(Recorder.STATE_STOPPED);
|
||||
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,40 +1,51 @@
|
||||
package com.stardust.scriptdroid.layout_inspector;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/10.
|
||||
*/
|
||||
|
||||
public class LayoutInspector implements AccessibilityDelegate {
|
||||
public class LayoutInspector {
|
||||
|
||||
private NodeInfo mCapture;
|
||||
private volatile NodeInfo mCapture;
|
||||
private volatile boolean mDumping = false;
|
||||
private Executor mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public NodeInfo captureCurrentWindow() {
|
||||
public void captureCurrentWindow() {
|
||||
AccessibilityService service = AccessibilityWatchDogService.getInstance();
|
||||
if (service == null) {
|
||||
mCapture = null;
|
||||
} else {
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
final AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root == null) {
|
||||
mCapture = null;
|
||||
} else {
|
||||
mCapture = NodeInfo.capture(root);
|
||||
mExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mDumping = true;
|
||||
mCapture = NodeInfo.capture(root);
|
||||
mDumping = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return mCapture;
|
||||
}
|
||||
|
||||
public boolean isDumping() {
|
||||
return mDumping;
|
||||
}
|
||||
|
||||
public void clearCapture() {
|
||||
mCapture = null;
|
||||
|
||||
@@ -81,7 +81,6 @@ public class LayoutHierarchyView extends MultiLevelListView {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void init() {
|
||||
mAdapter = new Adapter();
|
||||
setAdapter(mAdapter);
|
||||
@@ -204,6 +203,8 @@ public class LayoutHierarchyView extends MultiLevelListView {
|
||||
}
|
||||
|
||||
private String simplifyClassName(CharSequence className) {
|
||||
if (className == null)
|
||||
return null;
|
||||
String s = className.toString();
|
||||
if (s.startsWith("android.widget.")) {
|
||||
s = s.substring(15);
|
||||
@@ -214,7 +215,6 @@ public class LayoutHierarchyView extends MultiLevelListView {
|
||||
|
||||
private String getItemInfoDsc(ItemInfo itemInfo) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append(String.format(Locale.getDefault(), "level[%d], idx in level[%d/%d]",
|
||||
itemInfo.getLevel() + 1, /*Indexing starts from 0*/
|
||||
itemInfo.getIdxInLevel() + 1 /*Indexing starts from 0*/,
|
||||
|
||||
@@ -71,11 +71,6 @@ public class LayoutInspectView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void showLayoutBoundsView() {
|
||||
mLayoutBoundsView.setRootNode(AutoJs.getInstance().getLayoutInspector().captureCurrentWindow());
|
||||
backToLayoutBoundsView();
|
||||
}
|
||||
|
||||
public boolean isLayoutBoundsViewShowing() {
|
||||
return mCurrentView == mLayoutBoundsView;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.util.SparseArray;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.simple_action.FilterAction;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
@@ -123,24 +124,17 @@ public class AccessibilityActionConverter {
|
||||
if (source == null)
|
||||
return;
|
||||
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
|
||||
List<AccessibilityNodeInfo> editableList = FilterAction.EditableFilter.findEditable(allocator, service.getRootInActiveWindow());
|
||||
UiObject uiObject = new UiObject(service.getRootInActiveWindow(), allocator);
|
||||
List<UiObject> editableList = FilterAction.EditableFilter.findEditable(uiObject);
|
||||
int i = findInEditableList(editableList, source);
|
||||
recycle(editableList);
|
||||
sb.append("while(!input(").append(i).append(", \"").append(source.getText()).append("\"));");
|
||||
source.recycle();
|
||||
allocator.recycleAll();
|
||||
}
|
||||
|
||||
private void recycle(List<AccessibilityNodeInfo> list) {
|
||||
for (AccessibilityNodeInfo nodeInfo : list) {
|
||||
nodeInfo.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static int findInEditableList(List<AccessibilityNodeInfo> editableList, AccessibilityNodeInfo editable) {
|
||||
private static int findInEditableList(List<UiObject> editableList, AccessibilityNodeInfo editable) {
|
||||
int i = 0;
|
||||
for (AccessibilityNodeInfo nodeInfo : editableList) {
|
||||
for (UiObject nodeInfo : editableList) {
|
||||
if (AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).equals(AccessibilityNodeInfoHelper.getBoundsInScreen(editable))) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.scriptdroid.record.Recorder;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
@@ -27,6 +32,8 @@ public class AccessibilityActionRecorder extends Recorder.DefaultIMPL implements
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<Integer> EVENT_TYPES = new HashSet<>(Arrays.asList(AccessibilityEvent.TYPE_VIEW_CLICKED, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED, AccessibilityEvent.TYPE_VIEW_SCROLLED, AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED));
|
||||
|
||||
private static final long RECORD_TIME_OUT = 10 * 60 * 1000;
|
||||
|
||||
private boolean mShouldIgnoreFirstAction = false;
|
||||
@@ -64,6 +71,11 @@ public class AccessibilityActionRecorder extends Recorder.DefaultIMPL implements
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getEventTypes() {
|
||||
return EVENT_TYPES;
|
||||
}
|
||||
|
||||
private void checkTimeOut() {
|
||||
if (System.currentTimeMillis() - mRecordStartMillis > RECORD_TIME_OUT) {
|
||||
stop();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.stardust.scriptdroid.service;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
@@ -10,12 +9,16 @@ import com.stardust.autojs.runtime.JavascriptInterface;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.view.accessibility.AccessibilityService;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -32,10 +35,16 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
private static final SortedMap<Integer, AccessibilityDelegate> mDelegates = new TreeMap<>();
|
||||
private static final Object LOCK = new Object();
|
||||
private static AccessibilityWatchDogService instance;
|
||||
private Executor mExecutor = Executors.newSingleThreadExecutor();
|
||||
private static boolean containsAllEventTypes = false;
|
||||
private static final Set<Integer> eventTypes = new HashSet<>();
|
||||
|
||||
public static void addDelegate(int uniquePriority, AccessibilityDelegate delegate) {
|
||||
mDelegates.put(uniquePriority, delegate);
|
||||
Set<Integer> set = delegate.getEventTypes();
|
||||
if (set == null)
|
||||
containsAllEventTypes = true;
|
||||
else
|
||||
eventTypes.addAll(set);
|
||||
}
|
||||
|
||||
public static boolean isEnable() {
|
||||
@@ -49,25 +58,17 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
@Override
|
||||
public void onAccessibilityEvent(final AccessibilityEvent event) {
|
||||
Log.v(TAG, "onAccessibilityEvent: " + event);
|
||||
mExecutor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Map.Entry<Integer, AccessibilityDelegate> entry : mDelegates.entrySet()) {
|
||||
Log.v(TAG, "delegate: " + entry.getValue().getClass().getName());
|
||||
if (entry.getValue().onAccessibilityEvent(AccessibilityWatchDogService.this, event))
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeInfo getRootInActiveWindow() {
|
||||
try {
|
||||
return super.getRootInActiveWindow();
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
if (!containsAllEventTypes && !eventTypes.contains(event.getEventType()))
|
||||
return;
|
||||
for (Map.Entry<Integer, AccessibilityDelegate> entry : mDelegates.entrySet()) {
|
||||
AccessibilityDelegate delegate = entry.getValue();
|
||||
Set<Integer> types = delegate.getEventTypes();
|
||||
if (types != null && !delegate.getEventTypes().contains(event.getEventType()))
|
||||
continue;
|
||||
long start = System.currentTimeMillis();
|
||||
if (delegate.onAccessibilityEvent(AccessibilityWatchDogService.this, event))
|
||||
break;
|
||||
Log.v(TAG, "millis: " + (System.currentTimeMillis() - start) + " delegate: " + entry.getValue().getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import android.view.View;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.flurry.android.FlurryAgent;
|
||||
import com.stardust.pio.PFile;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.R;
|
||||
@@ -59,7 +60,6 @@ public abstract class BaseActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
@@ -2,14 +2,15 @@ package com.stardust.scriptdroid.ui.console;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import com.jraska.console.Console;
|
||||
import com.jraska.console.timber.ConsoleTree;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
import com.stardust.autojs.runtime.AbstractConsole;
|
||||
import com.stardust.scriptdroid.App;
|
||||
|
||||
|
||||
@@ -19,7 +20,7 @@ import timber.log.Timber;
|
||||
* Created by Stardust on 2017/4/2.
|
||||
*/
|
||||
|
||||
public class TimberConsole implements Console {
|
||||
public class TimberConsole extends AbstractConsole {
|
||||
|
||||
static {
|
||||
Timber.plant(new ConsoleTree.Builder()
|
||||
@@ -34,54 +35,29 @@ public class TimberConsole implements Console {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void i(@Nullable Object o) {
|
||||
i(o + "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void i(String str) {
|
||||
Timber.i(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void e(@Nullable String message) {
|
||||
Timber.e(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void e(@Nullable Object o) {
|
||||
e(o + "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void v(@Nullable String v) {
|
||||
Timber.v(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void v(@Nullable Object o) {
|
||||
v(o + "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@Nullable Object o) {
|
||||
log(o + "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(String str) {
|
||||
SpannableString spannableString = new SpannableString(str);
|
||||
spannableString.setSpan(new ForegroundColorSpan(Color.BLACK), 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
com.jraska.console.Console.writeLine(spannableString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
App.getApp().startActivity(new Intent(App.getApp(), ConsoleActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
protected void log(int level, CharSequence charSequence) {
|
||||
if (level == Log.DEBUG) {
|
||||
SpannableString spannable = new SpannableString(charSequence);
|
||||
spannable.setSpan(new ForegroundColorSpan(0xdd000000), 0, charSequence.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
Console.writeLine(spannable);
|
||||
} else {
|
||||
Timber.log(level, charSequence.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
com.jraska.console.Console.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
App.getApp().startActivity(new Intent(App.getApp(), ConsoleActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class CodeCompletion implements TextWatcher {
|
||||
mFunctions = functions;
|
||||
}
|
||||
|
||||
private String[] mFunctions = {"toast", "launchPackage", "launch", "launchApp", "click", "longClick", "scrollUp", "scrollDown", "select", "focus", "paste", "input", "sleep", "isStopped", "notStopped", "log", "err", "openConsole", "clearConsole", "shell", "getTexts", "getPackageName", "getActivityName", "setClip", "addAccessibilityDelegate"};
|
||||
private String[] mFunctions = {"toast", "launchPackage", "launch", "launchApp", "click", "longClick", "scrollUp", "scrollDown", "select", "focus", "paste", "input", "sleep", "isStopped", "notStopped", "println", "err", "openConsole", "clearConsole", "shell", "getTexts", "getPackageName", "getActivityName", "setClip", "addAccessibilityDelegate"};
|
||||
|
||||
private boolean searchCodeCompletion(String str) {
|
||||
Collection<CodeCompletionItem> c = searchWordCompletion(str);
|
||||
|
||||
@@ -34,7 +34,7 @@ public abstract class ScriptFileOperation {
|
||||
|
||||
@Override
|
||||
public void onStart(JavaScriptEngine engine, ScriptSource source) {
|
||||
AutoJs.getInstance().getScriptEngineService().getDefaultListener().onStart(engine, source);
|
||||
AutoJs.getInstance().getScriptEngineService().getDefaultScriptExecutionListener().onStart(engine, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.stardust.autojs.engine.JavaScriptEngine;
|
||||
import com.stardust.autojs.engine.JavaScriptEngineManager;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -46,8 +47,10 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private final List<JavaScriptEngine> mScriptEngines = new ArrayList<>();
|
||||
private Adapter mAdapter;
|
||||
private final ScriptEngineService mScriptEngineService = AutoJs.getInstance().getScriptEngineService();
|
||||
|
||||
public TaskListRecyclerView(Context context) {
|
||||
super(context);
|
||||
@@ -78,14 +81,14 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
|
||||
|
||||
public void updateEngineList() {
|
||||
mScriptEngines.clear();
|
||||
mScriptEngines.addAll(ScriptEngineService.getInstance().getEngines());
|
||||
mScriptEngines.addAll(mScriptEngineService.getEngines());
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
ScriptEngineService.getInstance().registerEngineLifecycleCallback(this);
|
||||
mScriptEngineService.registerEngineLifecycleCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,7 +100,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
ScriptEngineService.getInstance().unregisterEngineLifecycleCallback(this);
|
||||
mScriptEngineService.unregisterEngineLifecycleCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.view.ViewGroup;
|
||||
import com.stardust.app.Fragment;
|
||||
import com.stardust.autojs.ScriptEngineService;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.view.ViewBinder;
|
||||
import com.stardust.view.ViewBinding;
|
||||
import com.stardust.widget.SimpleAdapterDataObserver;
|
||||
@@ -74,6 +75,6 @@ public class TaskManagerFragment extends Fragment {
|
||||
|
||||
@ViewBinding.Click(R.id.close_all)
|
||||
private void closeAllRunningScripts() {
|
||||
ScriptEngineService.getInstance().stopAll();
|
||||
AutoJs.getInstance().getScriptEngineService().stopAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,5 +184,6 @@
|
||||
<string name="text_check_update">Check for updates</string>
|
||||
<string name="text_new_directory">New Directory</string>
|
||||
<string name="text_already_reset">已重置</string>
|
||||
<string name="text_layout_inspector_is_dumping">布局分析中,请稍后点击</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -215,6 +215,7 @@
|
||||
<string name="summary_guard_mode">在本软件界面无法运行自动操作命令以免误触</string>
|
||||
<string name="key_guard_mode">key_guard_mode</string>
|
||||
<string name="text_console_floating_window">控制台悬浮窗</string>
|
||||
<string name="text_layout_inspector_is_dumping">布局分析中,请稍后点击</string>
|
||||
|
||||
<string-array name="record_control_keys">
|
||||
<item>无</item>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.stardust.autojs;
|
||||
|
||||
import com.stardust.autojs.engine.JavaScriptEngine;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/1.
|
||||
*/
|
||||
|
||||
public class RunnableScriptExecution extends ScriptExecution.AbstarctScriptExecution implements ScriptExecution, Runnable {
|
||||
|
||||
private JavaScriptEngine mJavaScriptEngine;
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
private ScriptEngineService mScriptEngineService;
|
||||
|
||||
public RunnableScriptExecution(ScriptEngineService service, ScriptExecutionTask task) {
|
||||
super(task);
|
||||
mScriptEngineService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mJavaScriptEngine = mScriptEngineService.createScriptEngine();
|
||||
mScriptRuntime = mScriptEngineService.createScriptRuntime();
|
||||
mScriptExecutionTask.execute(mScriptRuntime, mJavaScriptEngine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptEngine getEngine() {
|
||||
return mJavaScriptEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptRuntime getRuntime() {
|
||||
return mScriptRuntime;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
import com.stardust.lang.ThreadCompat;
|
||||
import com.stardust.util.Supplier;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
@@ -20,6 +21,7 @@ import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/23.
|
||||
@@ -29,16 +31,6 @@ public class ScriptEngineService {
|
||||
|
||||
private static final String LOG_TAG = "ScriptEngineService";
|
||||
private static final EventBus EVENT_BUS = new EventBus();
|
||||
private static ScriptEngineService instance;
|
||||
|
||||
public static ScriptEngineService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void setInstance(ScriptEngineService service) {
|
||||
instance = service;
|
||||
}
|
||||
|
||||
private static final ScriptExecutionListener DEFAULT_LISTENER = new SimpleScriptExecutionListener() {
|
||||
@Override
|
||||
public void onStart(JavaScriptEngine engine, ScriptSource source) {
|
||||
@@ -54,31 +46,34 @@ public class ScriptEngineService {
|
||||
};
|
||||
|
||||
|
||||
private final ScriptRuntime mRuntime;
|
||||
private final Supplier<ScriptRuntime> mRuntimeSupplier;
|
||||
private final Context mContext;
|
||||
private final Console mConsole;
|
||||
private ScriptRuntime mGlobalScriptRuntime;
|
||||
private final Console mGlobalConsole;
|
||||
private final JavaScriptEngineManager mJavaScriptEngineManager;
|
||||
private final EngineLifecycleObserver mEngineLifecycleObserver = new EngineLifecycleObserver();
|
||||
private ScriptExecutionListener mDefaultScriptExecutionListener = DEFAULT_LISTENER;
|
||||
|
||||
ScriptEngineService(ScriptEngineServiceBuilder builder) {
|
||||
mRuntime = builder.mRuntime;
|
||||
mRuntimeSupplier = builder.mRuntimeSupplier;
|
||||
mContext = builder.mContext;
|
||||
mJavaScriptEngineManager = builder.mJavaScriptEngineManager;
|
||||
mConsole = builder.mConsole;
|
||||
mGlobalScriptRuntime = mRuntimeSupplier.get();
|
||||
mGlobalConsole = mGlobalScriptRuntime.console;
|
||||
mJavaScriptEngineManager.setEngineLifecycleCallback(mEngineLifecycleObserver);
|
||||
EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
public ScriptRuntime getRuntime() {
|
||||
return mRuntime;
|
||||
public Console getGlobalConsole() {
|
||||
return mGlobalConsole;
|
||||
}
|
||||
|
||||
public Console getConsole() {
|
||||
return mConsole;
|
||||
public ScriptExecutionListener getDefaultScriptExecutionListener() {
|
||||
return mDefaultScriptExecutionListener;
|
||||
}
|
||||
|
||||
public ScriptExecutionListener getDefaultListener() {
|
||||
return DEFAULT_LISTENER;
|
||||
public void setDefaultScriptExecutionListener(ScriptExecutionListener defaultScriptExecutionListener) {
|
||||
mDefaultScriptExecutionListener = defaultScriptExecutionListener;
|
||||
}
|
||||
|
||||
public JavaScriptEngine createScriptEngine() {
|
||||
@@ -87,6 +82,10 @@ public class ScriptEngineService {
|
||||
return engine;
|
||||
}
|
||||
|
||||
public ScriptRuntime createScriptRuntime() {
|
||||
return mRuntimeSupplier.get();
|
||||
}
|
||||
|
||||
public void registerEngineLifecycleCallback(JavaScriptEngineManager.EngineLifecycleCallback engineLifecycleCallback) {
|
||||
mEngineLifecycleObserver.registerCallback(engineLifecycleCallback);
|
||||
}
|
||||
@@ -96,18 +95,15 @@ public class ScriptEngineService {
|
||||
}
|
||||
|
||||
public static boolean causedByInterrupted(Throwable e) {
|
||||
return e.getCause() instanceof ScriptInterrupptedException;
|
||||
return e instanceof ScriptInterrupptedException || e.getCause() instanceof ScriptInterrupptedException;
|
||||
}
|
||||
|
||||
public ScriptExecution execute(ScriptExecutionTask task) {
|
||||
ScriptExecutionListener listener = task.getExecutionListenerOrDefault(DEFAULT_LISTENER);
|
||||
ScriptSource source = task.getSource();
|
||||
int mode = source.getExecutionMode();
|
||||
if ((mode & ScriptSource.EXECUTION_MODE_UI) != 0) {
|
||||
ScriptExecuteActivity.execute(mContext, task);
|
||||
return null;
|
||||
task.setDefaultListenerIfNeeded(mDefaultScriptExecutionListener);
|
||||
if (isUiMode(task)) {
|
||||
return ScriptExecuteActivity.execute(mContext, this, task);
|
||||
} else {
|
||||
RunnableScriptExecution scriptExecution = new RunnableScriptExecution(source, listener, task.getConfig());
|
||||
RunnableScriptExecution scriptExecution = new RunnableScriptExecution(this, task);
|
||||
if (task.getConfig().runInNewThread) {
|
||||
new ThreadCompat(scriptExecution).start();
|
||||
} else {
|
||||
@@ -117,6 +113,12 @@ public class ScriptEngineService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUiMode(ScriptExecutionTask task) {
|
||||
ScriptSource source = task.getSource();
|
||||
int mode = source.getExecutionMode();
|
||||
return (mode & ScriptSource.EXECUTION_MODE_UI) != 0;
|
||||
}
|
||||
|
||||
public ScriptExecution execute(ScriptSource source, ScriptExecutionListener listener, ExecutionConfig config) {
|
||||
return execute(new ScriptExecutionTask(source, listener, config));
|
||||
}
|
||||
@@ -126,16 +128,16 @@ public class ScriptEngineService {
|
||||
}
|
||||
|
||||
public ScriptExecution execute(ScriptSource source) {
|
||||
return execute(source, DEFAULT_LISTENER, ExecutionConfig.getDefault());
|
||||
return execute(source, mDefaultScriptExecutionListener, ExecutionConfig.getDefault());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onScriptExecution(ScriptExecutionEvent event) {
|
||||
if (event.getCode() == ScriptExecutionEvent.ON_START) {
|
||||
mConsole.v(DateFormat.getTimeInstance().format(new Date()) + " " + mContext.getString(R.string.text_start_running) + " " + event.getMessage());
|
||||
mGlobalConsole.verbose(DateFormat.getTimeInstance().format(new Date()) + " " + mContext.getString(R.string.text_start_running) + " " + event.getMessage());
|
||||
} else if (event.getCode() == ScriptExecutionEvent.ON_EXCEPTION) {
|
||||
mRuntime.toast(mContext.getString(R.string.text_error) + ": " + event.getMessage());
|
||||
mConsole.e(event.getMessage());
|
||||
mGlobalScriptRuntime.toast(mContext.getString(R.string.text_error) + ": " + event.getMessage());
|
||||
mGlobalConsole.error(event.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,9 +149,9 @@ public class ScriptEngineService {
|
||||
public void stopAllAndToast() {
|
||||
int n = stopAll();
|
||||
if (n > 0)
|
||||
mRuntime.toast(String.format(mContext.getString(R.string.text_already_stop_n_scripts), n));
|
||||
mGlobalScriptRuntime.toast(String.format(mContext.getString(R.string.text_already_stop_n_scripts), n));
|
||||
else
|
||||
mRuntime.toast(mContext.getString(R.string.text_no_running_script));
|
||||
mGlobalScriptRuntime.toast(mContext.getString(R.string.text_no_running_script));
|
||||
}
|
||||
|
||||
public String[] getGlobalFunctions() {
|
||||
@@ -160,31 +162,6 @@ public class ScriptEngineService {
|
||||
return mJavaScriptEngineManager.getEngines();
|
||||
}
|
||||
|
||||
private class RunnableScriptExecution extends ScriptExecutionTask implements ScriptExecution, Runnable {
|
||||
|
||||
private JavaScriptEngine mJavaScriptEngine;
|
||||
|
||||
RunnableScriptExecution(ScriptSource source, ScriptExecutionListener listener, ExecutionConfig config) {
|
||||
super(source, listener, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mJavaScriptEngine = createScriptEngine();
|
||||
execute(mRuntime, mJavaScriptEngine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptEngine getEngine() {
|
||||
return mJavaScriptEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptRuntime getRuntime() {
|
||||
return mRuntime;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EngineLifecycleObserver implements JavaScriptEngineManager.EngineLifecycleCallback {
|
||||
|
||||
private final Set<JavaScriptEngineManager.EngineLifecycleCallback> mEngineLifecycleCallbacks = new LinkedHashSet<>();
|
||||
@@ -211,6 +188,7 @@ public class ScriptEngineService {
|
||||
synchronized (mEngineLifecycleCallbacks) {
|
||||
mEngineLifecycleCallbacks.add(callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unregisterCallback(JavaScriptEngineManager.EngineLifecycleCallback callback) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import com.stardust.autojs.engine.JavaScriptEngineManager;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
import com.stardust.util.Supplier;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
@@ -12,17 +13,16 @@ import com.stardust.autojs.runtime.api.Console;
|
||||
|
||||
public class ScriptEngineServiceBuilder {
|
||||
|
||||
ScriptRuntime mRuntime;
|
||||
Supplier<ScriptRuntime> mRuntimeSupplier;
|
||||
Context mContext;
|
||||
Console mConsole;
|
||||
JavaScriptEngineManager mJavaScriptEngineManager;
|
||||
|
||||
public ScriptEngineServiceBuilder() {
|
||||
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder runtime(ScriptRuntime runtime) {
|
||||
mRuntime = runtime;
|
||||
public ScriptEngineServiceBuilder runtime(Supplier<ScriptRuntime> runtimeSupplier) {
|
||||
mRuntimeSupplier = runtimeSupplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,6 @@ public class ScriptEngineServiceBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder console(Console console) {
|
||||
mConsole = console;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptEngineServiceBuilder engineManger(JavaScriptEngineManager manager) {
|
||||
mJavaScriptEngineManager = manager;
|
||||
return this;
|
||||
|
||||
@@ -19,4 +19,34 @@ public interface ScriptExecution {
|
||||
ScriptExecutionListener getListener();
|
||||
|
||||
ExecutionConfig getConfig();
|
||||
|
||||
abstract class AbstarctScriptExecution implements ScriptExecution {
|
||||
|
||||
protected ScriptExecutionTask mScriptExecutionTask;
|
||||
|
||||
public AbstarctScriptExecution(ScriptExecutionTask task) {
|
||||
mScriptExecutionTask = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract JavaScriptEngine getEngine();
|
||||
|
||||
@Override
|
||||
public abstract ScriptRuntime getRuntime();
|
||||
|
||||
@Override
|
||||
public ScriptSource getSource() {
|
||||
return mScriptExecutionTask.getSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptExecutionListener getListener() {
|
||||
return mScriptExecutionTask.getListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecutionConfig getConfig() {
|
||||
return mScriptExecutionTask.getConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,14 +38,12 @@ public class ScriptExecutionTask implements Serializable {
|
||||
return mExecutionConfig;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void execute(ScriptRuntime runtime, JavaScriptEngine engine) {
|
||||
try {
|
||||
if ((mScriptSource.getExecutionMode() & ScriptSource.EXECUTION_MODE_AUTO) != 0) {
|
||||
runtime.ensureAccessibilityServiceEnabled();
|
||||
}
|
||||
mExecutionListener.onStart(engine, mScriptSource);
|
||||
engine.setTag("script", mScriptSource);
|
||||
mExecutionListener.onSuccess(engine, mScriptSource, engine.execute(mScriptSource));
|
||||
prepare(runtime, engine);
|
||||
doExecution(engine);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
mExecutionListener.onException(engine, mScriptSource, e);
|
||||
@@ -55,9 +53,29 @@ public class ScriptExecutionTask implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private void prepare(ScriptRuntime runtime, JavaScriptEngine engine) {
|
||||
if ((mScriptSource.getExecutionMode() & ScriptSource.EXECUTION_MODE_AUTO) != 0) {
|
||||
runtime.ensureAccessibilityServiceEnabled();
|
||||
}
|
||||
engine.put("__runtime__", runtime);
|
||||
engine.init();
|
||||
}
|
||||
|
||||
private void doExecution(JavaScriptEngine engine) {
|
||||
engine.setTag("script", mScriptSource);
|
||||
mExecutionListener.onStart(engine, mScriptSource);
|
||||
mExecutionListener.onSuccess(engine, mScriptSource, engine.execute(mScriptSource));
|
||||
}
|
||||
|
||||
public ScriptExecutionListener getExecutionListenerOrDefault(ScriptExecutionListener defaultListener) {
|
||||
if (mExecutionListener == null)
|
||||
return defaultListener;
|
||||
return mExecutionListener;
|
||||
}
|
||||
|
||||
public void setDefaultListenerIfNeeded(ScriptExecutionListener defaultScriptExecutionListener) {
|
||||
if (mExecutionListener == null) {
|
||||
mExecutionListener = defaultScriptExecutionListener;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ public abstract class JavaScriptEngineManager {
|
||||
public JavaScriptEngine createEngine() {
|
||||
JavaScriptEngine engine = createEngineInner();
|
||||
putProperties(engine);
|
||||
engine.init();
|
||||
addEngine(engine);
|
||||
return engine;
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
|
||||
public class NodeJsJavaScriptEngineManager extends RhinoJavaScriptEngineManager {
|
||||
|
||||
public NodeJsJavaScriptEngineManager(Context context, ScriptRuntime runtime) {
|
||||
super(context, runtime);
|
||||
public NodeJsJavaScriptEngineManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeJsJavaScriptEngine createEngineInner() {
|
||||
protected NodeJsJavaScriptEngine createEngineInner() {
|
||||
NodeJsJavaScriptEngine engine = new NodeJsJavaScriptEngine(this);
|
||||
initRequireBuilder(engine.getContext(), engine.getScriptable());
|
||||
return engine;
|
||||
|
||||
@@ -43,7 +43,6 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
|
||||
mThread = Thread.currentThread();
|
||||
mContext = createContext();
|
||||
mScriptable = createScope(mContext);
|
||||
setTag("create-traces", Arrays.toString(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,8 +52,6 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
|
||||
|
||||
@Override
|
||||
public Object execute(ScriptSource source) {
|
||||
setTag("execute-traces", Arrays.toString(Thread.currentThread().getStackTrace()));
|
||||
setTag("execute-source", source);
|
||||
return mContext.evaluateString(mScriptable, source.getScript(), "<script>", 1, null);
|
||||
}
|
||||
|
||||
@@ -72,17 +69,6 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
|
||||
public synchronized void destroy() {
|
||||
Log.d(LOG_TAG, "on destroy");
|
||||
Context.exit();
|
||||
// TODO: 2017/4/6 XXX :在这里回收内存池并不好
|
||||
final AccessibilityNodeInfoAllocator allocator = (AccessibilityNodeInfoAllocator) getTag("allocator");
|
||||
if (allocator != null) {
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
// FIXME: 2017/4/28
|
||||
//allocator.recycleAll();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
mEngineManager.removeEngine(this);
|
||||
}
|
||||
|
||||
@@ -93,10 +79,6 @@ public class RhinoJavaScriptEngine implements JavaScriptEngine {
|
||||
|
||||
@Override
|
||||
public synchronized Object getTag(String key) {
|
||||
Object tag = mTags.get(key);
|
||||
if (tag == null && key.equals("script")) {
|
||||
Log.i(LOG_TAG, mTags.entrySet().toString());
|
||||
}
|
||||
return mTags.get(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,11 @@ public class RhinoJavaScriptEngineManager extends JavaScriptEngineManager {
|
||||
private String mRequirePath = "";
|
||||
|
||||
|
||||
public RhinoJavaScriptEngineManager(android.content.Context context, ScriptRuntime runtime) {
|
||||
public RhinoJavaScriptEngineManager(android.content.Context context) {
|
||||
super(context);
|
||||
put("__runtime__", runtime);
|
||||
}
|
||||
|
||||
public RhinoJavaScriptEngine createEngineInner() {
|
||||
protected RhinoJavaScriptEngine createEngineInner() {
|
||||
RhinoJavaScriptEngine engine = new RhinoJavaScriptEngine(this);
|
||||
initRequireBuilder(engine.getContext(), engine.getScriptable());
|
||||
return engine;
|
||||
|
||||
@@ -5,9 +5,12 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.stardust.autojs.ExecutionConfig;
|
||||
import com.stardust.autojs.ScriptEngineService;
|
||||
import com.stardust.autojs.ScriptExecution;
|
||||
import com.stardust.autojs.ScriptExecutionListener;
|
||||
import com.stardust.autojs.ScriptExecutionTask;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
/**
|
||||
@@ -16,44 +19,54 @@ import com.stardust.autojs.script.ScriptSource;
|
||||
|
||||
public class ScriptExecuteActivity extends Activity {
|
||||
|
||||
private static final String EXTRA_TASK = "EXTRA_TASK";
|
||||
|
||||
private static ActivityScriptExecution execution;
|
||||
private Object mResult;
|
||||
private JavaScriptEngine mJavaScriptEngine;
|
||||
private ScriptExecutionListener mExecutionListener;
|
||||
private ScriptSource mScriptSource;
|
||||
|
||||
|
||||
public static void execute(Context context, ScriptExecutionTask task) {
|
||||
public static ActivityScriptExecution execute(Context context, ScriptEngineService service, ScriptExecutionTask task) {
|
||||
if (execution != null) {
|
||||
return null;
|
||||
}
|
||||
execution = new ActivityScriptExecution(service, task);
|
||||
context.startActivity(new Intent(context, ScriptExecuteActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_TASK, task));
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
return execution;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
handleIntent(getIntent());
|
||||
mJavaScriptEngine = ScriptEngineService.getInstance().createScriptEngine();
|
||||
mScriptSource = execution.getSource();
|
||||
mJavaScriptEngine = execution.getEngine();
|
||||
mExecutionListener = execution.getListener();
|
||||
runScript();
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
ScriptExecutionTask scriptExecutionTask = (ScriptExecutionTask) intent.getSerializableExtra(EXTRA_TASK);
|
||||
mExecutionListener = scriptExecutionTask.getListener();
|
||||
mScriptSource = scriptExecutionTask.getSource();
|
||||
}
|
||||
|
||||
private void runScript() {
|
||||
mJavaScriptEngine.put("activity", this);
|
||||
try {
|
||||
mJavaScriptEngine.setTag("script", mScriptSource);
|
||||
mResult = mJavaScriptEngine.execute(mScriptSource);
|
||||
prepare();
|
||||
doExecution();
|
||||
} catch (Exception e) {
|
||||
mExecutionListener.onException(mJavaScriptEngine, mScriptSource, e);
|
||||
super.finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void doExecution() {
|
||||
mJavaScriptEngine.setTag("script", mScriptSource);
|
||||
mExecutionListener.onStart(mJavaScriptEngine, mScriptSource);
|
||||
mResult = mJavaScriptEngine.execute(mScriptSource);
|
||||
}
|
||||
|
||||
private void prepare() {
|
||||
mJavaScriptEngine.put("activity", this);
|
||||
mJavaScriptEngine.put("__runtime__", execution.getRuntime());
|
||||
mJavaScriptEngine.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
mExecutionListener.onSuccess(mJavaScriptEngine, mScriptSource, mResult);
|
||||
@@ -65,6 +78,31 @@ public class ScriptExecuteActivity extends Activity {
|
||||
super.onDestroy();
|
||||
mJavaScriptEngine.put("activity", null);
|
||||
mJavaScriptEngine.destroy();
|
||||
execution = null;
|
||||
}
|
||||
|
||||
private static class ActivityScriptExecution extends ScriptExecution.AbstarctScriptExecution {
|
||||
|
||||
private JavaScriptEngine mJavaScriptEngine;
|
||||
private ScriptRuntime mScriptRuntime;
|
||||
|
||||
ActivityScriptExecution(ScriptEngineService service, ScriptExecutionTask task) {
|
||||
super(task);
|
||||
mJavaScriptEngine = service.createScriptEngine();
|
||||
mScriptRuntime = service.createScriptRuntime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaScriptEngine getEngine() {
|
||||
return mJavaScriptEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptRuntime getRuntime() {
|
||||
return mScriptRuntime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.stardust.autojs.runtime;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.autojs.runtime.api.Console;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/1.
|
||||
*/
|
||||
|
||||
public abstract class AbstractConsole implements Console {
|
||||
|
||||
protected abstract void log(int level, CharSequence charSequence);
|
||||
|
||||
public void println(int level, @Nullable Object data, Object... options) {
|
||||
log(level, format(data, options));
|
||||
}
|
||||
|
||||
public CharSequence format(@Nullable Object data, Object... options) {
|
||||
if (data == null)
|
||||
return "\n";
|
||||
if (options == null || options.length == 0)
|
||||
return data.toString();
|
||||
return String.format(data.toString(), options);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void verbose(@Nullable Object data, Object... options) {
|
||||
println(Log.VERBOSE, data, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void log(@Nullable Object data, Object... options) {
|
||||
println(Log.DEBUG, data, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(@Nullable Object data, Object... options) {
|
||||
println(Log.INFO, data, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(@Nullable Object data, Object... options) {
|
||||
println(Log.WARN, data, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(@Nullable Object data, Object... options) {
|
||||
println(Log.ERROR, data, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertTrue(boolean value, @Nullable Object data, Object... options) {
|
||||
if (!value) {
|
||||
println(Log.ASSERT, data, options);
|
||||
throw new ScriptStopException(new AssertionError(format(data, options)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,10 +53,10 @@ public class ScriptRuntime {
|
||||
|
||||
private AbstractShell mRootShell;
|
||||
|
||||
public ScriptRuntime(Context context, Console console, AccessibilityBridge accessibilityBridge) {
|
||||
public ScriptRuntime(Context context, Handler uiHandler, Console console, AccessibilityBridge accessibilityBridge) {
|
||||
mContext = context;
|
||||
mAccessibilityBridge = accessibilityBridge;
|
||||
mUIHandler = new Handler(mContext.getMainLooper());
|
||||
mUIHandler = uiHandler;
|
||||
app = new AppUtils(context);
|
||||
info = accessibilityBridge.getInfoProvider();
|
||||
this.console = console;
|
||||
@@ -94,8 +94,8 @@ public class ScriptRuntime {
|
||||
|
||||
|
||||
@JavascriptInterface
|
||||
public void shellExecNotReturnResultWithRoot(String cmd){
|
||||
if(mRootShell == null){
|
||||
public void shellExecNotReturnResultWithRoot(String cmd) {
|
||||
if (mRootShell == null) {
|
||||
mRootShell = new SlowShell(true);
|
||||
}
|
||||
mRootShell.exec(cmd);
|
||||
@@ -108,12 +108,7 @@ public class ScriptRuntime {
|
||||
|
||||
@JavascriptInterface
|
||||
public UiSelector selector(JavaScriptEngine engine) {
|
||||
AccessibilityNodeInfoAllocator allocator = (AccessibilityNodeInfoAllocator) engine.getTag("allocator");
|
||||
if (allocator == null) {
|
||||
allocator = new AccessibilityNodeInfoAllocator();
|
||||
engine.setTag("allocator", allocator);
|
||||
}
|
||||
return new UiSelector(mAccessibilityBridge, allocator);
|
||||
return new UiSelector(mAccessibilityBridge);
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
||||
@@ -11,33 +11,29 @@ import com.stardust.autojs.runtime.JavascriptInterface;
|
||||
public interface Console {
|
||||
|
||||
@JavascriptInterface
|
||||
void i(@Nullable Object o);
|
||||
void verbose(@Nullable Object data, Object... options);
|
||||
|
||||
@JavascriptInterface
|
||||
void i(String str);
|
||||
void log(@Nullable Object data, Object... options);
|
||||
|
||||
@JavascriptInterface
|
||||
void e(String message);
|
||||
void info(@Nullable Object data, Object... options);
|
||||
|
||||
@JavascriptInterface
|
||||
void e(@Nullable Object o);
|
||||
void warn(@Nullable Object data, Object... options);
|
||||
|
||||
@JavascriptInterface
|
||||
void v(String v);
|
||||
void error(@Nullable Object data, Object... options);
|
||||
|
||||
@JavascriptInterface
|
||||
void v(@Nullable Object o);
|
||||
void assertTrue(boolean value, @Nullable Object data, Object... options);
|
||||
|
||||
@JavascriptInterface
|
||||
void log(@Nullable Object o);
|
||||
|
||||
@JavascriptInterface
|
||||
void log(String string);
|
||||
void clear();
|
||||
|
||||
@JavascriptInterface
|
||||
void show();
|
||||
|
||||
@JavascriptInterface
|
||||
void clear();
|
||||
|
||||
void hide();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.autojs.runtime.AccessibilityBridge;
|
||||
import com.stardust.autojs.runtime.JavascriptInterface;
|
||||
import com.stardust.autojs.runtime.ScriptInterrupptedException;
|
||||
import com.stardust.autojs.runtime.ScriptStopException;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.automator.ActionArgument;
|
||||
import com.stardust.automator.UiGlobalSelector;
|
||||
@@ -66,7 +65,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
public void execute(AccessibilityService service, AccessibilityEvent event) {
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root != null) {
|
||||
result = findOf(root);
|
||||
result = findOf(new UiObject(root, mAllocator));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
private static final String TAG = "UiSelector";
|
||||
|
||||
private AccessibilityBridge mAccessibilityBridge;
|
||||
private AccessibilityNodeInfoAllocator mAllocator = AccessibilityNodeInfoAllocator.getGlobal();
|
||||
private AccessibilityNodeInfoAllocator mAllocator = null;
|
||||
|
||||
public UiSelector(AccessibilityBridge accessibilityBridge) {
|
||||
mAccessibilityBridge = accessibilityBridge;
|
||||
@@ -97,7 +96,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
if (service != null) {
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root != null) {
|
||||
return findOf(mAllocator, root);
|
||||
return findOf(new UiObject(root, mAllocator));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -142,7 +141,7 @@ public class UiSelector extends UiGlobalSelector {
|
||||
if (!id.contains(":")) {
|
||||
addFilter(new DfsFilter() {
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
String fullId = mAccessibilityBridge.getInfoProvider().getLatestPackage() + ":id/" + id;
|
||||
return fullId.equals(nodeInfo.getViewIdResourceName());
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ import com.stardust.autojs.runtime.JavascriptInterface;
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.api.AutomatorConfig;
|
||||
import com.stardust.automator.AccessibilityEventCommandHost;
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.automator.simple_action.SimpleAction;
|
||||
import com.stardust.automator.simple_action.ActionFactory;
|
||||
import com.stardust.automator.simple_action.ActionTarget;
|
||||
import com.stardust.util.DeveloperUtils;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/2.
|
||||
@@ -198,12 +198,8 @@ public class SimpleActionAutomator {
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root == null)
|
||||
return false;
|
||||
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
|
||||
simpleAction.setAllocator(allocator);
|
||||
Log.v(TAG, "performAction: " + simpleAction + " root = " + root);
|
||||
boolean result = simpleAction.perform(root);
|
||||
allocator.recycleAll();
|
||||
return result;
|
||||
return simpleAction.perform(new UiObject(root));
|
||||
}
|
||||
|
||||
private boolean isRunningPackageSelf() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@@ -69,6 +70,11 @@ public class AccessibilityEventCommandHost implements AccessibilityDelegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getEventTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void executeCommand(final Command command, final AccessibilityService service, final AccessibilityEvent event) {
|
||||
final Runnable r = new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -2,18 +2,16 @@ package com.stardust.automator;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.filter.BooleanFilter;
|
||||
import com.stardust.automator.filter.BoundsFilter;
|
||||
import com.stardust.automator.filter.DfsFilter;
|
||||
import com.stardust.automator.filter.IdFilter;
|
||||
import com.stardust.automator.filter.PackageNameFilter;
|
||||
import com.stardust.automator.filter.TextFilter;
|
||||
import com.stardust.automator.filter.ClassNameFilter;
|
||||
import com.stardust.automator.filter.DescFilter;
|
||||
import com.stardust.automator.filter.DfsFilter;
|
||||
import com.stardust.automator.filter.IdFilter;
|
||||
import com.stardust.automator.filter.ListFilter;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.filter.PackageNameFilter;
|
||||
import com.stardust.automator.filter.TextFilter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
@@ -173,7 +171,7 @@ public class UiGlobalSelector {
|
||||
public UiGlobalSelector drawingOrder(final int order) {
|
||||
mFilters.add(new DfsFilter() {
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && nodeInfo.getDrawingOrder() == order;
|
||||
}
|
||||
});
|
||||
@@ -352,26 +350,18 @@ public class UiGlobalSelector {
|
||||
return this;
|
||||
}
|
||||
|
||||
public UiObjectCollection findOf(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node) {
|
||||
List<AccessibilityNodeInfo> list = new ArrayList<>();
|
||||
public UiObjectCollection findOf(UiObject node) {
|
||||
List<UiObject> list = new ArrayList<>();
|
||||
list.add(node);
|
||||
for (ListFilter filter : mFilters) {
|
||||
list = filter.filter(allocator, list);
|
||||
list = filter.filter(list);
|
||||
}
|
||||
return UiObjectCollection.of(list);
|
||||
}
|
||||
|
||||
public UiObjectCollection findOf(AccessibilityNodeInfo node) {
|
||||
return findOf(AccessibilityNodeInfoAllocator.NONE, node);
|
||||
}
|
||||
|
||||
public UiObject findOneOf(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node) {
|
||||
public UiObject findOneOf(UiObject node) {
|
||||
// TODO: 2017/3/9 优化
|
||||
return new UiObject(findOf(allocator, node).get(0).getInfo());
|
||||
}
|
||||
|
||||
public UiObject findOneOf(AccessibilityNodeInfo node) {
|
||||
return findOneOf(AccessibilityNodeInfoAllocator.NONE, node);
|
||||
return findOf(node).get(0);
|
||||
}
|
||||
|
||||
public UiGlobalSelector addFilter(ListFilter filter) {
|
||||
|
||||
@@ -3,12 +3,14 @@ package com.stardust.automator;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CONTEXT_CLICK;
|
||||
@@ -26,15 +28,21 @@ import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.
|
||||
|
||||
public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
|
||||
private static final String TAG = "UiObject";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private AccessibilityNodeInfoAllocator mAllocator = null;
|
||||
private String mStackTrace = "";
|
||||
|
||||
public UiObject(Object info) {
|
||||
super(info);
|
||||
this(info, null);
|
||||
}
|
||||
|
||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator) {
|
||||
super(info);
|
||||
mAllocator = allocator;
|
||||
if (DEBUG)
|
||||
mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace());
|
||||
}
|
||||
|
||||
public UiObject parent() {
|
||||
@@ -46,11 +54,11 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
}
|
||||
|
||||
public UiObjectCollection find(UiGlobalSelector selector) {
|
||||
return selector.findOf((AccessibilityNodeInfo) getInfo());
|
||||
return selector.findOf(this);
|
||||
}
|
||||
|
||||
public UiObject findOne(UiGlobalSelector selector) {
|
||||
return selector.findOneOf((AccessibilityNodeInfo) getInfo());
|
||||
return selector.findOneOf(this);
|
||||
}
|
||||
|
||||
public UiObjectCollection children() {
|
||||
@@ -237,6 +245,10 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
return mAllocator.findAccessibilityNodeInfosByText(this, text);
|
||||
}
|
||||
|
||||
public List<UiObject> findByText(String text) {
|
||||
return compatListToUiObjectList(findAccessibilityNodeInfosByText(text), mAllocator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfoCompat> findAccessibilityNodeInfosByViewId(String viewId) {
|
||||
if (mAllocator == null)
|
||||
@@ -244,5 +256,37 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
return mAllocator.findAccessibilityNodeInfosByViewId(this, viewId);
|
||||
}
|
||||
|
||||
public List<UiObject> findByViewId(String viewId) {
|
||||
return compatListToUiObjectList(findAccessibilityNodeInfosByViewId(viewId), mAllocator);
|
||||
}
|
||||
|
||||
public static List<UiObject> compatListToUiObjectList(List<AccessibilityNodeInfoCompat> compats, AccessibilityNodeInfoAllocator allocator) {
|
||||
List<UiObject> uiObjects = new ArrayList<>(compats.size());
|
||||
for (AccessibilityNodeInfoCompat compat : compats) {
|
||||
uiObjects.add(new UiObject(compat.getInfo(), allocator));
|
||||
}
|
||||
return uiObjects;
|
||||
}
|
||||
|
||||
public static List<UiObject> compatListToUiObjectList(List<AccessibilityNodeInfoCompat> compats) {
|
||||
return compatListToUiObjectList(compats, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
try {
|
||||
super.recycle();
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, mStackTrace, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
super.recycle();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,28 +26,30 @@ import static android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.
|
||||
public class UiObjectCollection {
|
||||
|
||||
public static UiObjectCollection ofCompat(List<AccessibilityNodeInfoCompat> list) {
|
||||
return new UiObjectCollection(list);
|
||||
return new UiObjectCollection(UiObject.compatListToUiObjectList(list));
|
||||
}
|
||||
|
||||
public static UiObjectCollection of(List<AccessibilityNodeInfo> list) {
|
||||
List<AccessibilityNodeInfoCompat> compatList = new ArrayList<>(list.size());
|
||||
public static UiObjectCollection ofInfo(List<AccessibilityNodeInfo> list) {
|
||||
List<UiObject> compatList = new ArrayList<>(list.size());
|
||||
for (AccessibilityNodeInfo nodeInfo : list) {
|
||||
compatList.add(new AccessibilityNodeInfoCompat(nodeInfo));
|
||||
compatList.add(new UiObject(nodeInfo));
|
||||
}
|
||||
return new UiObjectCollection(compatList);
|
||||
}
|
||||
|
||||
private List<AccessibilityNodeInfoCompat> mNodes;
|
||||
private UiObject[] mUiObjects;
|
||||
public static UiObjectCollection of(List<UiObject> list) {
|
||||
return new UiObjectCollection(list);
|
||||
}
|
||||
|
||||
private List<UiObject> mNodes;
|
||||
|
||||
private UiObjectCollection(List<AccessibilityNodeInfoCompat> list) {
|
||||
private UiObjectCollection(List<UiObject> list) {
|
||||
mNodes = list;
|
||||
}
|
||||
|
||||
public boolean performAction(int action) {
|
||||
boolean fail = false;
|
||||
for (AccessibilityNodeInfoCompat node : mNodes) {
|
||||
for (UiObject node : mNodes) {
|
||||
if (!node.performAction(action)) {
|
||||
fail = true;
|
||||
}
|
||||
@@ -58,7 +60,7 @@ public class UiObjectCollection {
|
||||
public boolean performAction(int action, ActionArgument... arguments) {
|
||||
boolean fail = false;
|
||||
Bundle bundle = argumentsToBundle(arguments);
|
||||
for (AccessibilityNodeInfoCompat node : mNodes) {
|
||||
for (UiObject node : mNodes) {
|
||||
if (!node.performAction(action, bundle)) {
|
||||
fail = true;
|
||||
}
|
||||
@@ -182,18 +184,7 @@ public class UiObjectCollection {
|
||||
}
|
||||
|
||||
public UiObject get(int i) {
|
||||
ensureUiObjectAt(i);
|
||||
return mUiObjects[i];
|
||||
}
|
||||
|
||||
|
||||
private void ensureUiObjectAt(int i) {
|
||||
if (mUiObjects == null) {
|
||||
mUiObjects = new UiObject[mNodes.size()];
|
||||
}
|
||||
if (mUiObjects[i] == null) {
|
||||
mUiObjects[i] = new UiObject(mNodes.get(i).getInfo());
|
||||
}
|
||||
return mNodes.get(i);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
@@ -201,9 +192,8 @@ public class UiObjectCollection {
|
||||
}
|
||||
|
||||
public UiObjectCollection each(Consumer<UiObject> consumer) {
|
||||
for (int i = 0; i < mNodes.size(); i++) {
|
||||
ensureUiObjectAt(i);
|
||||
consumer.accept(mUiObjects[i]);
|
||||
for (UiObject uiObject : mNodes) {
|
||||
consumer.accept(uiObject);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ package com.stardust.automator.filter;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -31,14 +32,14 @@ public class BooleanFilter extends DfsFilter {
|
||||
|
||||
public interface BooleanSupplier {
|
||||
|
||||
boolean get(AccessibilityNodeInfo node);
|
||||
boolean get(UiObject node);
|
||||
|
||||
}
|
||||
|
||||
public static final BooleanSupplier CHECKABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isCheckable();
|
||||
}
|
||||
};
|
||||
@@ -46,7 +47,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier CHECKED = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isChecked();
|
||||
}
|
||||
};
|
||||
@@ -54,7 +55,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier FOCUSABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isFocusable();
|
||||
}
|
||||
};
|
||||
@@ -62,7 +63,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier FOCUSED = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isFocused();
|
||||
}
|
||||
};
|
||||
@@ -70,7 +71,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier VISIBLE_TO_USER = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isVisibleToUser();
|
||||
}
|
||||
};
|
||||
@@ -78,7 +79,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier ACCESSIBILITY_FOCUSED = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isAccessibilityFocused();
|
||||
}
|
||||
};
|
||||
@@ -86,7 +87,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier SELECTED = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isSelected();
|
||||
}
|
||||
};
|
||||
@@ -94,7 +95,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier CLICKABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isClickable();
|
||||
}
|
||||
};
|
||||
@@ -102,7 +103,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier LONG_CLICKABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isLongClickable();
|
||||
}
|
||||
};
|
||||
@@ -110,7 +111,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier ENABLED = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isEnabled();
|
||||
}
|
||||
};
|
||||
@@ -119,7 +120,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier PASSWORD = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isPassword();
|
||||
}
|
||||
};
|
||||
@@ -127,7 +128,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier SCROLLABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isScrollable();
|
||||
}
|
||||
};
|
||||
@@ -135,14 +136,14 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier EDITABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isEditable();
|
||||
}
|
||||
};
|
||||
public static final BooleanSupplier CONTENT_INVALID = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isContentInvalid();
|
||||
}
|
||||
};
|
||||
@@ -151,7 +152,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isContextClickable();
|
||||
}
|
||||
};
|
||||
@@ -159,7 +160,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier MULTI_LINE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isMultiLine();
|
||||
}
|
||||
};
|
||||
@@ -167,7 +168,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
public static final BooleanSupplier DISMISSABLE = new BooleanSupplier() {
|
||||
|
||||
@Override
|
||||
public boolean get(AccessibilityNodeInfo node) {
|
||||
public boolean get(UiObject node) {
|
||||
return node.isDismissable();
|
||||
}
|
||||
};
|
||||
@@ -181,7 +182,7 @@ public class BooleanFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
return nodeInfo != null && mBooleanSupplier.get(nodeInfo) == mExceptedValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ public class BoundsFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
if (mType == TYPE_CONTAINS) {
|
||||
return AccessibilityNodeInfoHelper.getBoundsInScreen(nodeInfo).contains(mBounds);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -10,7 +10,7 @@ public class ClassNameFilter {
|
||||
|
||||
private static final KeyGetter CLASS_NAME_GETTER = new KeyGetter() {
|
||||
@Override
|
||||
public String getKey(AccessibilityNodeInfo nodeInfo) {
|
||||
public String getKey(UiObject nodeInfo) {
|
||||
CharSequence charSequence = nodeInfo.getClassName();
|
||||
return charSequence == null ? null : charSequence.toString();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -10,7 +10,7 @@ public class DescFilter {
|
||||
|
||||
private static final KeyGetter DESC_GETTER = new KeyGetter() {
|
||||
@Override
|
||||
public String getKey(AccessibilityNodeInfo nodeInfo) {
|
||||
public String getKey(UiObject nodeInfo) {
|
||||
CharSequence charSequence = nodeInfo.getContentDescription();
|
||||
return charSequence == null ? null : charSequence.toString();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -14,41 +12,41 @@ import java.util.List;
|
||||
public abstract class DfsFilter implements ListFilter, Filter {
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, List<AccessibilityNodeInfo> nodes) {
|
||||
ArrayList<AccessibilityNodeInfo> list = new ArrayList<>();
|
||||
for (AccessibilityNodeInfo node : nodes) {
|
||||
public List<UiObject> filter(List<UiObject> nodes) {
|
||||
ArrayList<UiObject> list = new ArrayList<>();
|
||||
for (UiObject node : nodes) {
|
||||
if (isIncluded(node)) {
|
||||
list.add(node);
|
||||
}
|
||||
filterChildren(allocator, node, list);
|
||||
filterChildren(node, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node) {
|
||||
ArrayList<AccessibilityNodeInfo> list = new ArrayList<>();
|
||||
public List<UiObject> filter(UiObject node) {
|
||||
ArrayList<UiObject> list = new ArrayList<>();
|
||||
if (isIncluded(node)) {
|
||||
list.add(node);
|
||||
}
|
||||
filterChildren(allocator, node, list);
|
||||
filterChildren(node, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private void filterChildren(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo parent, List<AccessibilityNodeInfo> list) {
|
||||
private void filterChildren(UiObject parent, List<UiObject> list) {
|
||||
for (int i = 0; i < parent.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = allocator.getChild(parent, i);
|
||||
UiObject child = parent.child(i);
|
||||
if (child == null)
|
||||
continue;
|
||||
boolean included = isIncluded(child);
|
||||
if (included) {
|
||||
list.add(child);
|
||||
}
|
||||
filterChildren(allocator, child, list);
|
||||
filterChildren(child, list);
|
||||
if (!included) {
|
||||
child.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract boolean isIncluded(AccessibilityNodeInfo nodeInfo);
|
||||
protected abstract boolean isIncluded(UiObject nodeInfo);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -12,6 +10,6 @@ import java.util.List;
|
||||
|
||||
public interface Filter {
|
||||
|
||||
List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node);
|
||||
List<UiObject> filter(UiObject node);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -15,7 +13,7 @@ public class IdFilter extends ListFilter.Default {
|
||||
private static final KeyGetter ID_GETTER = new KeyGetter() {
|
||||
|
||||
@Override
|
||||
public String getKey(AccessibilityNodeInfo nodeInfo) {
|
||||
public String getKey(UiObject nodeInfo) {
|
||||
return nodeInfo.getViewIdResourceName();
|
||||
}
|
||||
};
|
||||
@@ -47,8 +45,8 @@ public class IdFilter extends ListFilter.Default {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node) {
|
||||
return allocator.findAccessibilityNodeInfosByViewId(node, mId);
|
||||
public List<UiObject> filter(UiObject node) {
|
||||
return node.findByViewId(mId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -8,5 +8,5 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
public interface KeyGetter {
|
||||
|
||||
String getKey(AccessibilityNodeInfo nodeInfo);
|
||||
String getKey(UiObject nodeInfo);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -13,15 +11,15 @@ import java.util.List;
|
||||
|
||||
public interface ListFilter {
|
||||
|
||||
List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, List<AccessibilityNodeInfo> nodes);
|
||||
List<UiObject> filter(List<UiObject> nodes);
|
||||
|
||||
abstract class Default implements Filter, ListFilter {
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, List<AccessibilityNodeInfo> nodes) {
|
||||
List<AccessibilityNodeInfo> list = new ArrayList<>();
|
||||
for (AccessibilityNodeInfo node : nodes) {
|
||||
list.addAll(filter(allocator, node));
|
||||
public List<UiObject> filter(List<UiObject> nodes) {
|
||||
List<UiObject> list = new ArrayList<>();
|
||||
for (UiObject node : nodes) {
|
||||
list.addAll(filter(node));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -10,7 +10,7 @@ public class PackageNameFilter {
|
||||
|
||||
private static final KeyGetter PACKAGE_NAME_GETTER = new KeyGetter() {
|
||||
@Override
|
||||
public String getKey(AccessibilityNodeInfo nodeInfo) {
|
||||
public String getKey(UiObject nodeInfo) {
|
||||
CharSequence charSequence = nodeInfo.getPackageName();
|
||||
return charSequence == null ? null : charSequence.toString();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -16,7 +16,7 @@ public class StringContainsFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
String key = mKeyGetter.getKey(nodeInfo);
|
||||
return key != null && key.contains(mContains);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -17,7 +17,7 @@ public class StringEndsWithFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
String key = mKeyGetter.getKey(nodeInfo);
|
||||
return key != null && key.endsWith(mSuffix);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -17,7 +17,7 @@ public class StringEqualsFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
String key = mKeyGetter.getKey(nodeInfo);
|
||||
if(key != null){
|
||||
return key.equals(mText);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -17,7 +17,7 @@ public class StringMatchesFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
String key = mKeyGetter.getKey(nodeInfo);
|
||||
return key != null && key.matches(mRegex);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
@@ -17,7 +17,7 @@ public class StringStartsWithFilter extends DfsFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIncluded(AccessibilityNodeInfo nodeInfo) {
|
||||
protected boolean isIncluded(UiObject nodeInfo) {
|
||||
String key = mKeyGetter.getKey(nodeInfo);
|
||||
return key != null && key.startsWith(mPrefix);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.filter;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,7 +12,7 @@ public class TextFilter extends ListFilter.Default {
|
||||
|
||||
private static final KeyGetter TEXT_GETTER = new KeyGetter() {
|
||||
@Override
|
||||
public String getKey(AccessibilityNodeInfo nodeInfo) {
|
||||
public String getKey(UiObject nodeInfo) {
|
||||
CharSequence charSequence = nodeInfo.getText();
|
||||
return charSequence == null ? null : charSequence.toString();
|
||||
}
|
||||
@@ -48,7 +46,7 @@ public class TextFilter extends ListFilter.Default {
|
||||
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node) {
|
||||
return allocator.findAccessibilityNodeInfosByText(node, mText);
|
||||
public List<UiObject> filter(UiObject node) {
|
||||
return node.findByText(mText);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.stardust.automator.simple_action;
|
||||
import android.util.SparseArray;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
|
||||
/**
|
||||
@@ -14,36 +15,36 @@ public interface Able {
|
||||
SparseArray<Able> ABLE_MAP = new SparseArrayEntries<Able>()
|
||||
.entry(AccessibilityNodeInfo.ACTION_CLICK, new Able() {
|
||||
@Override
|
||||
public boolean isAble(AccessibilityNodeInfo nodeInfo) {
|
||||
public boolean isAble(UiObject nodeInfo) {
|
||||
return nodeInfo.isClickable();
|
||||
}
|
||||
})
|
||||
.entry(AccessibilityNodeInfo.ACTION_LONG_CLICK, new Able() {
|
||||
@Override
|
||||
public boolean isAble(AccessibilityNodeInfo nodeInfo) {
|
||||
public boolean isAble(UiObject nodeInfo) {
|
||||
return nodeInfo.isLongClickable();
|
||||
}
|
||||
})
|
||||
.entry(AccessibilityNodeInfo.ACTION_FOCUS, new Able() {
|
||||
@Override
|
||||
public boolean isAble(AccessibilityNodeInfo nodeInfo) {
|
||||
public boolean isAble(UiObject nodeInfo) {
|
||||
return nodeInfo.isFocusable();
|
||||
}
|
||||
})
|
||||
.entry(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, new Able() {
|
||||
@Override
|
||||
public boolean isAble(AccessibilityNodeInfo nodeInfo) {
|
||||
public boolean isAble(UiObject nodeInfo) {
|
||||
return nodeInfo.isScrollable();
|
||||
}
|
||||
})
|
||||
.entry(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, new Able() {
|
||||
@Override
|
||||
public boolean isAble(AccessibilityNodeInfo nodeInfo) {
|
||||
public boolean isAble(UiObject nodeInfo) {
|
||||
return nodeInfo.isScrollable();
|
||||
}
|
||||
})
|
||||
.sparseArray();
|
||||
|
||||
boolean isAble(AccessibilityNodeInfo node);
|
||||
boolean isAble(UiObject node);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.os.Bundle;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -45,7 +46,7 @@ public class ActionFactory {
|
||||
return new SearchTargetAction(action, new FilterAction.EditableFilter(index)) {
|
||||
|
||||
@Override
|
||||
protected void performAction(AccessibilityNodeInfo node) {
|
||||
protected void performAction(UiObject node) {
|
||||
Bundle args = new Bundle();
|
||||
args.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
|
||||
node.performAction(getAction(), args);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@@ -20,16 +18,16 @@ public class DepthFirstSearchTargetAction extends SearchTargetAction {
|
||||
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeInfo searchTarget(AccessibilityNodeInfo n) {
|
||||
public UiObject searchTarget(UiObject n) {
|
||||
if (n == null)
|
||||
return null;
|
||||
if (mAble.isAble(n))
|
||||
return n;
|
||||
for (int i = 0; i < n.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = getAllocator().getChild(n, i);
|
||||
UiObject child = n.child(i);
|
||||
if (child == null)
|
||||
continue;
|
||||
AccessibilityNodeInfo node = searchTarget(child);
|
||||
UiObject node = searchTarget(child);
|
||||
if (node != null)
|
||||
return node;
|
||||
else
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@@ -18,7 +17,7 @@ public abstract class FilterAction extends SimpleAction {
|
||||
|
||||
public interface Filter {
|
||||
|
||||
List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root);
|
||||
List<UiObject> filter(UiObject root);
|
||||
}
|
||||
|
||||
public static class TextFilter implements Filter {
|
||||
@@ -32,8 +31,8 @@ public abstract class FilterAction extends SimpleAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root) {
|
||||
List<AccessibilityNodeInfo> list = allocator.findAccessibilityNodeInfosByText(root, mText);
|
||||
public List<UiObject> filter(UiObject root) {
|
||||
List<UiObject> list = root.findByText(mText);
|
||||
if (mIndex == -1)
|
||||
return list;
|
||||
if (mIndex >= list.size())
|
||||
@@ -59,11 +58,11 @@ public abstract class FilterAction extends SimpleAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root) {
|
||||
return Collections.singletonList(findAccessibilityNodeInfosByBounds(allocator, root));
|
||||
public List<UiObject> filter(UiObject root) {
|
||||
return Collections.singletonList(findAccessibilityNodeInfosByBounds(root));
|
||||
}
|
||||
|
||||
private AccessibilityNodeInfo findAccessibilityNodeInfosByBounds(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root) {
|
||||
private UiObject findAccessibilityNodeInfosByBounds(UiObject root) {
|
||||
if (root == null)
|
||||
return null;
|
||||
Rect rect = new Rect();
|
||||
@@ -72,10 +71,10 @@ public abstract class FilterAction extends SimpleAction {
|
||||
return root;
|
||||
}
|
||||
for (int i = 0; i < root.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = allocator.getChild(root, i);
|
||||
UiObject child = root.child(i);
|
||||
if (child == null)
|
||||
continue;
|
||||
AccessibilityNodeInfo nodeInfo = findAccessibilityNodeInfosByBounds(allocator, child);
|
||||
UiObject nodeInfo = findAccessibilityNodeInfosByBounds(child);
|
||||
if (nodeInfo != null)
|
||||
return nodeInfo;
|
||||
else
|
||||
@@ -101,8 +100,8 @@ public abstract class FilterAction extends SimpleAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root) {
|
||||
List<AccessibilityNodeInfo> editableList = findEditable(allocator, root);
|
||||
public List<UiObject> filter(UiObject root) {
|
||||
List<UiObject> editableList = findEditable(root);
|
||||
if (mIndex == -1)
|
||||
return editableList;
|
||||
if (mIndex >= editableList.size())
|
||||
@@ -110,16 +109,16 @@ public abstract class FilterAction extends SimpleAction {
|
||||
return Collections.singletonList(editableList.get(mIndex));
|
||||
}
|
||||
|
||||
public static List<AccessibilityNodeInfo> findEditable(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root) {
|
||||
public static List<UiObject> findEditable(UiObject root) {
|
||||
if (root == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (root.isEditable()) {
|
||||
return Collections.singletonList(root);
|
||||
}
|
||||
List<AccessibilityNodeInfo> list = new LinkedList<>();
|
||||
List<UiObject> list = new LinkedList<>();
|
||||
for (int i = 0; i < root.getChildCount(); i++) {
|
||||
list.addAll(findEditable(allocator, allocator.getChild(root, i)));
|
||||
list.addAll(findEditable(root.child(i)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -141,8 +140,8 @@ public abstract class FilterAction extends SimpleAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccessibilityNodeInfo> filter(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo root) {
|
||||
return allocator.findAccessibilityNodeInfosByViewId(root, mId);
|
||||
public List<UiObject> filter(UiObject root) {
|
||||
return root.findByViewId(mId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,16 +159,15 @@ public abstract class FilterAction extends SimpleAction {
|
||||
mFilter = filter;
|
||||
}
|
||||
|
||||
public boolean perform(AccessibilityNodeInfo root) {
|
||||
@Override
|
||||
public boolean perform(UiObject root) {
|
||||
if (root == null)
|
||||
return false;
|
||||
List<AccessibilityNodeInfo> list = mFilter.filter(getAllocator(), root);
|
||||
boolean succeed = perform(list);
|
||||
AccessibilityNodeInfoAllocator.recycleList(root, list);
|
||||
return succeed;
|
||||
List<UiObject> list = mFilter.filter(root);
|
||||
return perform(list);
|
||||
}
|
||||
|
||||
public abstract boolean perform(List<AccessibilityNodeInfo> nodes);
|
||||
public abstract boolean perform(List<UiObject> nodes);
|
||||
|
||||
public static class SimpleFilterAction extends FilterAction {
|
||||
|
||||
@@ -181,11 +179,11 @@ public abstract class FilterAction extends SimpleAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform(List<AccessibilityNodeInfo> nodes) {
|
||||
public boolean perform(List<UiObject> nodes) {
|
||||
if (nodes == null || nodes.isEmpty())
|
||||
return false;
|
||||
boolean succeed = true;
|
||||
for (AccessibilityNodeInfo nodeInfo : nodes) {
|
||||
for (UiObject nodeInfo : nodes) {
|
||||
if (!nodeInfo.performAction(mAction)) {
|
||||
succeed = false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -20,27 +18,27 @@ public class ScrollAction extends SimpleAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform(AccessibilityNodeInfo root) {
|
||||
List<AccessibilityNodeInfo> scrollableNodes = findScrollableNodes(root);
|
||||
public boolean perform(UiObject root) {
|
||||
List<UiObject> scrollableNodes = findScrollableNodes(root);
|
||||
boolean result = mIndex < scrollableNodes.size() && scrollableNodes.get(mIndex).performAction(mAction);
|
||||
recycle(scrollableNodes, root);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void recycle(List<AccessibilityNodeInfo> list, AccessibilityNodeInfo root) {
|
||||
for (AccessibilityNodeInfo nodeInfo : list) {
|
||||
private void recycle(List<UiObject> list, UiObject root) {
|
||||
for (UiObject nodeInfo : list) {
|
||||
if (nodeInfo != root)
|
||||
nodeInfo.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
private List<AccessibilityNodeInfo> findScrollableNodes(AccessibilityNodeInfo root) {
|
||||
List<AccessibilityNodeInfo> list = new ArrayList<>();
|
||||
findScrollableNodes(getAllocator(), root, list);
|
||||
private List<UiObject> findScrollableNodes(UiObject root) {
|
||||
List<UiObject> list = new ArrayList<>();
|
||||
findScrollableNodes(root, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private static boolean findScrollableNodes(AccessibilityNodeInfoAllocator allocator, AccessibilityNodeInfo node, List<AccessibilityNodeInfo> list) {
|
||||
private static boolean findScrollableNodes(UiObject node, List<UiObject> list) {
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -48,10 +46,10 @@ public class ScrollAction extends SimpleAction {
|
||||
list.add(node);
|
||||
}
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = allocator.getChild(node, i);
|
||||
UiObject child = node.child(i);
|
||||
if (child == null)
|
||||
continue;
|
||||
if (!findScrollableNodes(allocator, child, list))
|
||||
if (!findScrollableNodes(child, list))
|
||||
child.recycle();
|
||||
}
|
||||
return node.isScrollable();
|
||||
|
||||
@@ -2,9 +2,8 @@ package com.stardust.automator.simple_action;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@@ -14,15 +13,15 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
|
||||
private static final String TAG = ScrollMaxAction.class.getSimpleName();
|
||||
private int mScrollAction;
|
||||
private AccessibilityNodeInfo mMaxScrollableNode;
|
||||
private AccessibilityNodeInfo mRootNode;
|
||||
private UiObject mMaxScrollableNode;
|
||||
private UiObject mRootNode;
|
||||
|
||||
public ScrollMaxAction(int scrollAction) {
|
||||
mScrollAction = scrollAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform(AccessibilityNodeInfo rootNodeInfo) {
|
||||
public boolean perform(UiObject rootNodeInfo) {
|
||||
reset();
|
||||
mRootNode = rootNodeInfo;
|
||||
findMaxScrollableNodeInfo(rootNodeInfo);
|
||||
@@ -38,7 +37,7 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
mMaxScrollableNode = mRootNode = null;
|
||||
}
|
||||
|
||||
private void findMaxScrollableNodeInfo(AccessibilityNodeInfo nodeInfo) {
|
||||
private void findMaxScrollableNodeInfo(UiObject nodeInfo) {
|
||||
if (nodeInfo == null)
|
||||
return;
|
||||
if (nodeInfo.isScrollable()) {
|
||||
@@ -51,7 +50,7 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < nodeInfo.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = getAllocator().getChild(nodeInfo, i);
|
||||
UiObject child = nodeInfo.child(i);
|
||||
if (child != null) {
|
||||
findMaxScrollableNodeInfo(child);
|
||||
if (mMaxScrollableNode != child) {
|
||||
@@ -61,7 +60,7 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
}
|
||||
}
|
||||
|
||||
private long getAreaInScreen(AccessibilityNodeInfo nodeInfo) {
|
||||
private long getAreaInScreen(UiObject nodeInfo) {
|
||||
Rect rect = new Rect();
|
||||
nodeInfo.getBoundsInScreen(rect);
|
||||
long area = ((long) rect.width()) * rect.height();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -19,20 +19,19 @@ public abstract class SearchTargetAction extends FilterAction {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean perform(List<AccessibilityNodeInfo> nodes) {
|
||||
public boolean perform(List<UiObject> nodes) {
|
||||
boolean performed = false;
|
||||
for (AccessibilityNodeInfo node : nodes) {
|
||||
for (UiObject node : nodes) {
|
||||
node = searchTarget(node);
|
||||
if (node != null) {
|
||||
performAction(node);
|
||||
performed = true;
|
||||
node.recycle();
|
||||
}
|
||||
}
|
||||
return performed;
|
||||
}
|
||||
|
||||
protected void performAction(AccessibilityNodeInfo node) {
|
||||
protected void performAction(UiObject node) {
|
||||
node.performAction(mAction);
|
||||
}
|
||||
|
||||
@@ -40,7 +39,7 @@ public abstract class SearchTargetAction extends FilterAction {
|
||||
return mAction;
|
||||
}
|
||||
|
||||
public AccessibilityNodeInfo searchTarget(AccessibilityNodeInfo node) {
|
||||
public UiObject searchTarget(UiObject node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@@ -23,19 +19,16 @@ public class SearchUpTargetAction extends SearchTargetAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeInfo searchTarget(AccessibilityNodeInfo n) {
|
||||
AccessibilityNodeInfo node = n;
|
||||
public UiObject searchTarget(UiObject n) {
|
||||
UiObject node = n;
|
||||
int i = 0;
|
||||
List<AccessibilityNodeInfo> list = new ArrayList<>();
|
||||
while (node != null && !mAble.isAble(node)) {
|
||||
i++;
|
||||
if (i > LOOP_MAX) {
|
||||
node.recycle();
|
||||
return null;
|
||||
}
|
||||
AccessibilityNodeInfo parent = getAllocator().getParent(node);
|
||||
list.add(node);
|
||||
node = parent;
|
||||
node = node.parent();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
|
||||
import java.util.List;
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
@@ -14,12 +8,10 @@ import java.util.List;
|
||||
|
||||
public abstract class SimpleAction {
|
||||
|
||||
|
||||
private volatile AccessibilityNodeInfoAllocator mAllocator = AccessibilityNodeInfoAllocator.NONE;
|
||||
private volatile boolean mValid = true;
|
||||
private volatile boolean mResult = false;
|
||||
|
||||
public abstract boolean perform(AccessibilityNodeInfo root);
|
||||
public abstract boolean perform(UiObject root);
|
||||
|
||||
public boolean getResult() {
|
||||
return mResult;
|
||||
@@ -37,12 +29,4 @@ public abstract class SimpleAction {
|
||||
return mValid;
|
||||
}
|
||||
|
||||
public AccessibilityNodeInfoAllocator getAllocator() {
|
||||
return mAllocator;
|
||||
}
|
||||
|
||||
public void setAllocator(@NonNull AccessibilityNodeInfoAllocator allocator) {
|
||||
mAllocator = allocator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
package com.stardust.automator.simple_action;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.os.Looper;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.automator.UiObject;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Vector;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
@@ -50,6 +46,11 @@ public class SimpleActionPerformHost implements AccessibilityDelegate {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getEventTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void performAction(AccessibilityNodeInfo root, SimpleAction simpleAction) {
|
||||
mExecutor.execute(new SimpleActionPerformRunnable(root, simpleAction));
|
||||
}
|
||||
@@ -78,7 +79,7 @@ public class SimpleActionPerformHost implements AccessibilityDelegate {
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "perform simpleAction: " + mSimpleAction);
|
||||
if (mSimpleAction.perform(mRoot)) {
|
||||
if (mSimpleAction.perform(new UiObject(mRoot))) {
|
||||
mSimpleAction.setResult(true);
|
||||
onActionPerformed(mSimpleAction);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.stardust.view.accessibility;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/14.
|
||||
*/
|
||||
@@ -12,4 +16,12 @@ public interface AccessibilityDelegate {
|
||||
|
||||
boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event);
|
||||
|
||||
/**
|
||||
* 返回调用onAccessibilityEvent时的EventType的集合。如果需要对所有EventType都有效,返回null。
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
Set<Integer> getEventTypes();
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/9.
|
||||
*/
|
||||
@@ -35,10 +40,19 @@ public class AccessibilityInfoProvider implements AccessibilityDelegate {
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
setLatestComponent(event.getPackageName(), event.getClassName());
|
||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||
if (root != null)
|
||||
setLatestComponent(root.getPackageName(), event.getClassName());
|
||||
else
|
||||
setLatestComponent(event.getPackageName(), event.getClassName());
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getEventTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private synchronized void setLatestComponent(CharSequence latestPackage, CharSequence latestClass) {
|
||||
if (latestPackage == null)
|
||||
return;
|
||||
|
||||
@@ -126,13 +126,9 @@ public class AccessibilityNodeInfoAllocator {
|
||||
|
||||
public static void recycleList(AccessibilityNodeInfo root, List<AccessibilityNodeInfo> list) {
|
||||
for (AccessibilityNodeInfo nodeInfo : list) {
|
||||
if (nodeInfo != root) {
|
||||
try {
|
||||
nodeInfo.recycle();
|
||||
}catch (IllegalStateException e){
|
||||
// FIXME: 2017/4/30
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (nodeInfo != root && nodeInfo != null) {
|
||||
//// FIXME: 2017/5/1 Issue #180
|
||||
nodeInfo.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.stardust.view.accessibility;
|
||||
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/2.
|
||||
*/
|
||||
|
||||
public abstract class AccessibilityService extends android.accessibilityservice.AccessibilityService {
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeInfo getRootInActiveWindow() {
|
||||
try {
|
||||
return super.getRootInActiveWindow();
|
||||
} catch (Exception ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
common/src/main/java/com/stardust/util/Supplier.java
Normal file
9
common/src/main/java/com/stardust/util/Supplier.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package com.stardust.util;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/1.
|
||||
*/
|
||||
|
||||
public interface Supplier<T> {
|
||||
T get();
|
||||
}
|
||||
Reference in New Issue
Block a user