Fix fucking issue #193 by removing recycle in finalize
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'com.getkeepsafe.dexcount'
|
||||||
def AAVersion = '4.2.0'
|
def AAVersion = '4.2.0'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@@ -49,6 +50,20 @@ android {
|
|||||||
pickFirst 'org/mozilla/javascript/*.java.orig'
|
pickFirst 'org/mozilla/javascript/*.java.orig'
|
||||||
pickFirst 'org/mozilla/javascript/tools/resources/*.properties'
|
pickFirst 'org/mozilla/javascript/tools/resources/*.properties'
|
||||||
}
|
}
|
||||||
|
dexcount {
|
||||||
|
format = "list"
|
||||||
|
includeClasses = false
|
||||||
|
includeFieldCount = true
|
||||||
|
includeTotalMethodCount = false
|
||||||
|
orderByMethodCount = false
|
||||||
|
verbose = false
|
||||||
|
maxTreeDepth = Integer.MAX_VALUE
|
||||||
|
teamCityIntegration = false
|
||||||
|
enableForInstantRun = false
|
||||||
|
teamCitySlug = null
|
||||||
|
runOnEachAssemble = true
|
||||||
|
maxMethodCount = 64000
|
||||||
|
}
|
||||||
configurations.all {
|
configurations.all {
|
||||||
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
|
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import android.os.Bundle;
|
|||||||
import android.support.annotation.Keep;
|
import android.support.annotation.Keep;
|
||||||
import android.support.multidex.MultiDexApplication;
|
import android.support.multidex.MultiDexApplication;
|
||||||
|
|
||||||
import com.flurry.android.FlurryAgent;
|
|
||||||
import com.squareup.leakcanary.LeakCanary;
|
import com.squareup.leakcanary.LeakCanary;
|
||||||
import com.stardust.app.SimpleActivityLifecycleCallbacks;
|
import com.stardust.app.SimpleActivityLifecycleCallbacks;
|
||||||
import com.stardust.app.VolumeChangeObserver;
|
import com.stardust.app.VolumeChangeObserver;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.stardust.scriptdroid.autojs;
|
package com.stardust.scriptdroid.autojs;
|
||||||
|
|
||||||
import com.flurry.android.FlurryAgent;
|
|
||||||
import com.stardust.autojs.execution.ScriptExecution;
|
import com.stardust.autojs.execution.ScriptExecution;
|
||||||
import com.stardust.autojs.execution.ScriptExecutionListener;
|
import com.stardust.autojs.execution.ScriptExecutionListener;
|
||||||
import com.stardust.scriptdroid.App;
|
import com.stardust.scriptdroid.App;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
import com.stardust.automator.UiObject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -74,19 +74,24 @@ public class NodeInfo {
|
|||||||
this(new AccessibilityNodeInfoCompat(node));
|
this(new AccessibilityNodeInfoCompat(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
|
||||||
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
|
public static NodeInfo capture(@NonNull UiObject root) {
|
||||||
NodeInfo nodeInfo = new NodeInfo(root);
|
NodeInfo nodeInfo = new NodeInfo(root);
|
||||||
for (int i = 0; i < root.getChildCount(); i++) {
|
int childCount = root.getChildCount();
|
||||||
AccessibilityNodeInfo child = allocator.getChild(root, i);
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
UiObject child = root.child(i);
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
nodeInfo.children.add(capture(child));
|
nodeInfo.children.add(capture(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allocator.recycleAll();
|
|
||||||
return nodeInfo;
|
return nodeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
||||||
|
UiObject r = UiObject.createRoot(root);
|
||||||
|
return capture(r);
|
||||||
|
}
|
||||||
|
|
||||||
public List<NodeInfo> getChildren() {
|
public List<NodeInfo> getChildren() {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,13 +123,11 @@ public class AccessibilityActionConverter {
|
|||||||
AccessibilityNodeInfo source = event.getSource();
|
AccessibilityNodeInfo source = event.getSource();
|
||||||
if (source == null)
|
if (source == null)
|
||||||
return;
|
return;
|
||||||
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
|
UiObject uiObject = UiObject.createRoot(service.getRootInActiveWindow());
|
||||||
UiObject uiObject = new UiObject(service.getRootInActiveWindow(), allocator);
|
|
||||||
List<UiObject> editableList = FilterAction.EditableFilter.findEditable(uiObject);
|
List<UiObject> editableList = FilterAction.EditableFilter.findEditable(uiObject);
|
||||||
int i = findInEditableList(editableList, source);
|
int i = findInEditableList(editableList, source);
|
||||||
sb.append("while(!input(").append(i).append(", \"").append(source.getText()).append("\"));");
|
sb.append("while(!input(").append(i).append(", \"").append(source.getText()).append("\"));");
|
||||||
source.recycle();
|
source.recycle();
|
||||||
allocator.recycleAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int findInEditableList(List<UiObject> editableList, AccessibilityNodeInfo editable) {
|
private static int findInEditableList(List<UiObject> editableList, AccessibilityNodeInfo editable) {
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
package com.stardust.scriptdroid.ui;
|
package com.stardust.scriptdroid.ui;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.RequiresApi;
|
import android.support.annotation.RequiresApi;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.view.View;
|
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;
|
import com.stardust.scriptdroid.R;
|
||||||
import com.stardust.scriptdroid.tool.UpdateChecker;
|
|
||||||
import com.stardust.scriptdroid.tool.VersionInfo;
|
import com.stardust.scriptdroid.tool.VersionInfo;
|
||||||
import com.stardust.scriptdroid.ui.update.UpdateCheckDialog;
|
|
||||||
import com.stardust.theme.ThemeColorManager;
|
import com.stardust.theme.ThemeColorManager;
|
||||||
import com.stardust.util.BackPressedHandler;
|
import com.stardust.util.BackPressedHandler;
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package com.stardust.scriptdroid.ui.console;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import com.stardust.autojs.runtime.api.AbstractConsole;
|
import com.stardust.autojs.runtime.api.AbstractConsole;
|
||||||
import com.stardust.autojs.runtime.api.Console;
|
import com.stardust.autojs.runtime.api.Console;
|
||||||
import com.stardust.enhancedfloaty.FloatyService;
|
import com.stardust.enhancedfloaty.FloatyService;
|
||||||
import com.stardust.enhancedfloaty.ResizableExpandableFloatyWindow;
|
import com.stardust.enhancedfloaty.ResizableExpandableFloatyWindow;
|
||||||
|
import com.stardust.scriptdroid.R;
|
||||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||||
import com.stardust.util.UiHandler;
|
import com.stardust.util.UiHandler;
|
||||||
|
|
||||||
@@ -82,7 +84,12 @@ public class StardustConsole extends AbstractConsole {
|
|||||||
mUiHandler.post(new Runnable() {
|
mUiHandler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
FloatyService.addWindow(mFloatyWindow);
|
try {
|
||||||
|
FloatyService.addWindow(mFloatyWindow);
|
||||||
|
} catch (WindowManager.BadTokenException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
mUiHandler.toast(R.string.text_no_floating_window_permission);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,22 +61,22 @@ public class ProcessShell extends AbstractShell implements AutoCloseable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exit() {
|
public void exit() {
|
||||||
if(mProcess != null) {
|
if (mProcess != null) {
|
||||||
mProcess.destroy();
|
mProcess.destroy();
|
||||||
mProcess = null;
|
mProcess = null;
|
||||||
}
|
}
|
||||||
if(mSucceedReader != null){
|
if (mSucceedReader != null) {
|
||||||
try{
|
try {
|
||||||
mSucceedReader.close();
|
mSucceedReader.close();
|
||||||
}catch (IOException ignored){
|
} catch (IOException ignored) {
|
||||||
|
|
||||||
}
|
}
|
||||||
mSucceedReader = null;
|
mSucceedReader = null;
|
||||||
}
|
}
|
||||||
if(mErrorReader != null){
|
if (mErrorReader != null) {
|
||||||
try{
|
try {
|
||||||
mErrorReader.close();
|
mErrorReader.close();
|
||||||
}catch (IOException ignored){
|
} catch (IOException ignored) {
|
||||||
|
|
||||||
}
|
}
|
||||||
mErrorReader = null;
|
mErrorReader = null;
|
||||||
@@ -158,8 +158,8 @@ public class ProcessShell extends AbstractShell implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Result exec(String[] commands, boolean isRoot) {
|
public static Result exec(String[] commands, boolean isRoot) {
|
||||||
try(ProcessShell shell = new ProcessShell(isRoot)){
|
try (ProcessShell shell = new ProcessShell(isRoot)) {
|
||||||
for(String command : commands){
|
for (String command : commands) {
|
||||||
shell.exec(command);
|
shell.exec(command);
|
||||||
}
|
}
|
||||||
shell.exec(COMMAND_EXIT);
|
shell.exec(COMMAND_EXIT);
|
||||||
@@ -173,4 +173,5 @@ public class ProcessShell extends AbstractShell implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ public class UiSelector extends UiGlobalSelector {
|
|||||||
public void execute(AccessibilityService service, AccessibilityEvent event) {
|
public void execute(AccessibilityService service, AccessibilityEvent event) {
|
||||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
result = findOf(new UiObject(root, mAllocator));
|
result = findOf(UiObject.createRoot(root, mAllocator));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ public class UiSelector extends UiGlobalSelector {
|
|||||||
if (service != null) {
|
if (service != null) {
|
||||||
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||||
if (root != null) {
|
if (root != null) {
|
||||||
return findOf(new UiObject(root, mAllocator));
|
return findOf(UiObject.createRoot(root, mAllocator));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ public class SimpleActionAutomator {
|
|||||||
if (root == null)
|
if (root == null)
|
||||||
return false;
|
return false;
|
||||||
Log.v(TAG, "performAction: " + simpleAction + " root = " + root);
|
Log.v(TAG, "performAction: " + simpleAction + " root = " + root);
|
||||||
return simpleAction.perform(new UiObject(root));
|
return simpleAction.perform(UiObject.createRoot(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isRunningPackageSelf() {
|
private boolean isRunningPackageSelf() {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.stardust.automator.simple_action;
|
||||||
|
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
|
import com.stardust.automator.test.TestUiObject;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/5/5.
|
||||||
|
*/
|
||||||
|
public class DepthFirstSearchTargetActionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void perform() {
|
||||||
|
DepthFirstSearchTargetAction action = new DepthFirstSearchTargetAction(AccessibilityNodeInfo.ACTION_CLICK, new FilterAction.Filter() {
|
||||||
|
@Override
|
||||||
|
public List<UiObject> filter(UiObject root) {
|
||||||
|
List<UiObject> list = new ArrayList<>();
|
||||||
|
for (int i = 0; i < root.getChildCount(); i++) {
|
||||||
|
list.add(root.child(i));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
TestUiObject root = new TestUiObject(5);
|
||||||
|
action.perform(root);
|
||||||
|
System.out.println(TestUiObject.max);
|
||||||
|
assertEquals(1, TestUiObject.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.stardust.automator.simple_action;
|
||||||
|
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
|
import com.stardust.automator.test.TestUiObject;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/5/5.
|
||||||
|
*/
|
||||||
|
public class ScrollMaxActionTest {
|
||||||
|
@Test
|
||||||
|
public void perform() throws Exception {
|
||||||
|
ScrollMaxAction action = new ScrollMaxAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
|
||||||
|
UiObject root = new TestUiObject(20);
|
||||||
|
action.perform(root);
|
||||||
|
System.out.println(TestUiObject.max);
|
||||||
|
assertEquals(1, TestUiObject.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ package com.stardust.automator;
|
|||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.util.Pools;
|
||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
@@ -9,6 +11,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
|||||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -30,27 +34,62 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
|
|
||||||
private static final String TAG = "UiObject";
|
private static final String TAG = "UiObject";
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
private static int notRecycledCount = 0;
|
||||||
|
|
||||||
|
public static UiObject createRoot(AccessibilityNodeInfo root) {
|
||||||
|
return new UiObject(root, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UiObject createRoot(AccessibilityNodeInfo root, AccessibilityNodeInfoAllocator allocator) {
|
||||||
|
return new UiObject(root, allocator, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private AccessibilityNodeInfoAllocator mAllocator = null;
|
private AccessibilityNodeInfoAllocator mAllocator = null;
|
||||||
private String mStackTrace = "";
|
private String mStackTrace = "";
|
||||||
|
private boolean mIsRootNode = false;
|
||||||
|
|
||||||
public UiObject(Object info) {
|
public UiObject(Object info) {
|
||||||
this(info, null);
|
this(info, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator) {
|
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, boolean isRootNode) {
|
||||||
super(info);
|
super(info);
|
||||||
|
mIsRootNode = isRootNode;
|
||||||
mAllocator = allocator;
|
mAllocator = allocator;
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace());
|
mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace());
|
||||||
}
|
}
|
||||||
|
|
||||||
public UiObject parent() {
|
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator) {
|
||||||
return new UiObject(getParent().getInfo());
|
this(info, allocator, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public UiObject parent() {
|
||||||
|
try {
|
||||||
|
AccessibilityNodeInfoCompat parent = super.getParent();
|
||||||
|
if (parent == null)
|
||||||
|
return null;
|
||||||
|
return new UiObject(parent.getInfo());
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// FIXME: 2017/5/5
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public UiObject child(int i) {
|
public UiObject child(int i) {
|
||||||
return new UiObject(getChild(i).getInfo());
|
try {
|
||||||
|
AccessibilityNodeInfoCompat child = super.getChild(i);
|
||||||
|
if (child == null)
|
||||||
|
return null;
|
||||||
|
return new UiObject(child.getInfo());
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// FIXME: 2017/5/5
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UiObjectCollection find(UiGlobalSelector selector) {
|
public UiObjectCollection find(UiGlobalSelector selector) {
|
||||||
@@ -110,6 +149,31 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
return performAction(action, bundle);
|
return performAction(action, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAction(int action, Bundle bundle) {
|
||||||
|
try {
|
||||||
|
return super.performAction(action);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// FIXME: 2017/5/5
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAction(int action) {
|
||||||
|
try {
|
||||||
|
return super.performAction(action);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// FIXME: 2017/5/5
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AccessibilityNodeInfoAllocator getAllocator() {
|
||||||
|
return mAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
private static Bundle argumentsToBundle(ActionArgument[] arguments) {
|
private static Bundle argumentsToBundle(ActionArgument[] arguments) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
for (ActionArgument arg : arguments) {
|
for (ActionArgument arg : arguments) {
|
||||||
@@ -263,7 +327,8 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
public static List<UiObject> compatListToUiObjectList(List<AccessibilityNodeInfoCompat> compats, AccessibilityNodeInfoAllocator allocator) {
|
public static List<UiObject> compatListToUiObjectList(List<AccessibilityNodeInfoCompat> compats, AccessibilityNodeInfoAllocator allocator) {
|
||||||
List<UiObject> uiObjects = new ArrayList<>(compats.size());
|
List<UiObject> uiObjects = new ArrayList<>(compats.size());
|
||||||
for (AccessibilityNodeInfoCompat compat : compats) {
|
for (AccessibilityNodeInfoCompat compat : compats) {
|
||||||
uiObjects.add(new UiObject(compat.getInfo(), allocator));
|
if (compat != null)
|
||||||
|
uiObjects.add(new UiObject(compat.getInfo(), allocator));
|
||||||
}
|
}
|
||||||
return uiObjects;
|
return uiObjects;
|
||||||
}
|
}
|
||||||
@@ -281,12 +346,5 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
try {
|
|
||||||
super.recycle();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
super.finalize();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ public class DepthFirstSearchTargetAction extends SearchTargetAction {
|
|||||||
UiObject node = searchTarget(child);
|
UiObject node = searchTarget(child);
|
||||||
if (node != null)
|
if (node != null)
|
||||||
return node;
|
return node;
|
||||||
else
|
|
||||||
child.recycle();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ public abstract class FilterAction extends SimpleAction {
|
|||||||
UiObject nodeInfo = findAccessibilityNodeInfosByBounds(child);
|
UiObject nodeInfo = findAccessibilityNodeInfosByBounds(child);
|
||||||
if (nodeInfo != null)
|
if (nodeInfo != null)
|
||||||
return nodeInfo;
|
return nodeInfo;
|
||||||
else
|
|
||||||
child.recycle();
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,24 +34,29 @@ public class ScrollAction extends SimpleAction {
|
|||||||
|
|
||||||
private List<UiObject> findScrollableNodes(UiObject root) {
|
private List<UiObject> findScrollableNodes(UiObject root) {
|
||||||
List<UiObject> list = new ArrayList<>();
|
List<UiObject> list = new ArrayList<>();
|
||||||
findScrollableNodes(root, list);
|
if (root != null) {
|
||||||
|
findScrollableNodes(root, list);
|
||||||
|
if (root.isScrollable()) {
|
||||||
|
list.add(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean findScrollableNodes(UiObject node, List<UiObject> list) {
|
private static void findScrollableNodes(UiObject node, List<UiObject> list) {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
return false;
|
return;
|
||||||
}
|
|
||||||
if (node.isScrollable()) {
|
|
||||||
list.add(node);
|
|
||||||
}
|
}
|
||||||
for (int i = 0; i < node.getChildCount(); i++) {
|
for (int i = 0; i < node.getChildCount(); i++) {
|
||||||
UiObject child = node.child(i);
|
UiObject child = node.child(i);
|
||||||
if (child == null)
|
if (child == null)
|
||||||
continue;
|
continue;
|
||||||
if (!findScrollableNodes(child, list))
|
findScrollableNodes(child, list);
|
||||||
|
if (child.isScrollable()) {
|
||||||
|
list.add(child);
|
||||||
|
} else {
|
||||||
child.recycle();
|
child.recycle();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return node.isScrollable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import android.util.Log;
|
|||||||
|
|
||||||
import com.stardust.automator.UiObject;
|
import com.stardust.automator.UiObject;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/1/27.
|
* Created by Stardust on 2017/1/27.
|
||||||
*/
|
*/
|
||||||
@@ -15,6 +18,7 @@ public class ScrollMaxAction extends SimpleAction {
|
|||||||
private int mScrollAction;
|
private int mScrollAction;
|
||||||
private UiObject mMaxScrollableNode;
|
private UiObject mMaxScrollableNode;
|
||||||
private UiObject mRootNode;
|
private UiObject mRootNode;
|
||||||
|
private Set<UiObject> mRecycledMaxUiObjects = new HashSet<>();
|
||||||
|
|
||||||
public ScrollMaxAction(int scrollAction) {
|
public ScrollMaxAction(int scrollAction) {
|
||||||
mScrollAction = scrollAction;
|
mScrollAction = scrollAction;
|
||||||
@@ -35,6 +39,7 @@ public class ScrollMaxAction extends SimpleAction {
|
|||||||
mMaxScrollableNode.recycle();
|
mMaxScrollableNode.recycle();
|
||||||
}
|
}
|
||||||
mMaxScrollableNode = mRootNode = null;
|
mMaxScrollableNode = mRootNode = null;
|
||||||
|
mRecycledMaxUiObjects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findMaxScrollableNodeInfo(UiObject nodeInfo) {
|
private void findMaxScrollableNodeInfo(UiObject nodeInfo) {
|
||||||
@@ -44,8 +49,10 @@ public class ScrollMaxAction extends SimpleAction {
|
|||||||
if (mMaxScrollableNode == null) {
|
if (mMaxScrollableNode == null) {
|
||||||
mMaxScrollableNode = nodeInfo;
|
mMaxScrollableNode = nodeInfo;
|
||||||
} else if (getAreaInScreen(mMaxScrollableNode) < getAreaInScreen(nodeInfo)) {
|
} else if (getAreaInScreen(mMaxScrollableNode) < getAreaInScreen(nodeInfo)) {
|
||||||
if (mMaxScrollableNode != mRootNode)
|
if (mMaxScrollableNode != mRootNode) {
|
||||||
|
mRecycledMaxUiObjects.add(mMaxScrollableNode);
|
||||||
mMaxScrollableNode.recycle();
|
mMaxScrollableNode.recycle();
|
||||||
|
}
|
||||||
mMaxScrollableNode = nodeInfo;
|
mMaxScrollableNode = nodeInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +60,7 @@ public class ScrollMaxAction extends SimpleAction {
|
|||||||
UiObject child = nodeInfo.child(i);
|
UiObject child = nodeInfo.child(i);
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
findMaxScrollableNodeInfo(child);
|
findMaxScrollableNodeInfo(child);
|
||||||
if (mMaxScrollableNode != child) {
|
if (mMaxScrollableNode != child && !mRecycledMaxUiObjects.contains(child)) {
|
||||||
child.recycle();
|
child.recycle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ public class SearchUpTargetAction extends SearchTargetAction {
|
|||||||
while (node != null && !mAble.isAble(node)) {
|
while (node != null && !mAble.isAble(node)) {
|
||||||
i++;
|
i++;
|
||||||
if (i > LOOP_MAX) {
|
if (i > LOOP_MAX) {
|
||||||
node.recycle();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
node = node.parent();
|
node = node.parent();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class SimpleActionPerformHost implements AccessibilityDelegate {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Log.i(TAG, "perform simpleAction: " + mSimpleAction);
|
Log.i(TAG, "perform simpleAction: " + mSimpleAction);
|
||||||
if (mSimpleAction.perform(new UiObject(mRoot))) {
|
if (mSimpleAction.perform(UiObject.createRoot(mRoot))) {
|
||||||
mSimpleAction.setResult(true);
|
mSimpleAction.setResult(true);
|
||||||
onActionPerformed(mSimpleAction);
|
onActionPerformed(mSimpleAction);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package com.stardust.automator.test;
|
||||||
|
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/5/5.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TestUiObject extends UiObject {
|
||||||
|
|
||||||
|
public static int count = 0;
|
||||||
|
public static int max = 0;
|
||||||
|
private static Random random = new Random();
|
||||||
|
|
||||||
|
private int mHashCode = random.nextInt();
|
||||||
|
private boolean mRecycled = false;
|
||||||
|
private int mChildCount;
|
||||||
|
|
||||||
|
public TestUiObject(int i) {
|
||||||
|
super(null);
|
||||||
|
count++;
|
||||||
|
max = Math.max(max, count);
|
||||||
|
mChildCount = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public TestUiObject() {
|
||||||
|
this(Math.max(0, random.nextInt(6) - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UiObject child(int i) {
|
||||||
|
return new TestUiObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UiObject parent() {
|
||||||
|
return new TestUiObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChildCount() {
|
||||||
|
return mChildCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrollable() {
|
||||||
|
return random.nextInt(4) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClickable() {
|
||||||
|
return random.nextBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getBoundsInScreen(Rect outBounds) {
|
||||||
|
int left = random.nextInt(1080);
|
||||||
|
int top = random.nextInt(1920);
|
||||||
|
int right = random.nextInt(1080 - left) + left;
|
||||||
|
int bottom = random.nextInt(1920 - top) + top;
|
||||||
|
outBounds.set(left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAction(int action, Bundle bundle) {
|
||||||
|
return random.nextBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean performAction(int action) {
|
||||||
|
return random.nextBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recycle() {
|
||||||
|
if (mRecycled) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
mRecycled = true;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UiObject@" + Integer.toHexString(hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mHashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -106,7 +106,7 @@ public class AccessibilityNodeInfoAllocator {
|
|||||||
return notRecycledCount;
|
return notRecycledCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessibilityNodeInfo add(@Nullable AccessibilityNodeInfo nodeInfo) {
|
public AccessibilityNodeInfo add(@Nullable AccessibilityNodeInfo nodeInfo) {
|
||||||
String stackTrace = DEBUG ? Arrays.toString(Thread.currentThread().getStackTrace()) : null;
|
String stackTrace = DEBUG ? Arrays.toString(Thread.currentThread().getStackTrace()) : null;
|
||||||
if (nodeInfo != null)
|
if (nodeInfo != null)
|
||||||
mAccessibilityNodeInfoList.put(nodeInfo, stackTrace);
|
mAccessibilityNodeInfoList.put(nodeInfo, stackTrace);
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.stardust.automator.filter;
|
||||||
|
|
||||||
|
import com.stardust.automator.test.TestUiObject;
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/5/5.
|
||||||
|
*/
|
||||||
|
public class DfsFilterTest {
|
||||||
|
|
||||||
|
private static class RandomDfsFilter extends DfsFilter {
|
||||||
|
|
||||||
|
private Random mRandom = new Random();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isIncluded(UiObject nodeInfo) {
|
||||||
|
return mRandom.nextBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void filter() throws Exception {
|
||||||
|
DfsFilter filter = new RandomDfsFilter();
|
||||||
|
UiObject root = new TestUiObject(10);
|
||||||
|
List<UiObject> list = filter.filter(root);
|
||||||
|
for (UiObject uiObject : list) {
|
||||||
|
if (root != uiObject)
|
||||||
|
uiObject.recycle();
|
||||||
|
}
|
||||||
|
System.out.println(TestUiObject.max);
|
||||||
|
assertEquals(1, TestUiObject.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.stardust.automator.simple_action;
|
||||||
|
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
|
import com.stardust.automator.test.TestUiObject;
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/5/5.
|
||||||
|
*/
|
||||||
|
public class ScrollActionTest {
|
||||||
|
@Test
|
||||||
|
public void perform() throws Exception {
|
||||||
|
ScrollAction action = new ScrollAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, 0);
|
||||||
|
UiObject root = new TestUiObject(5);
|
||||||
|
action.perform(root);
|
||||||
|
System.out.println(TestUiObject.max);
|
||||||
|
assertEquals(1, TestUiObject.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:2.3.1'
|
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||||
|
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.4'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
Reference in New Issue
Block a user