Fix fucking issue #193 by removing recycle in finalize
This commit is contained in:
@@ -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.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.util.Pools;
|
||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import android.util.Log;
|
||||
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.AccessibilityNodeInfoHelper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -30,27 +34,62 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
|
||||
private static final String TAG = "UiObject";
|
||||
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 String mStackTrace = "";
|
||||
private boolean mIsRootNode = false;
|
||||
|
||||
public UiObject(Object info) {
|
||||
this(info, null);
|
||||
}
|
||||
|
||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator) {
|
||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, boolean isRootNode) {
|
||||
super(info);
|
||||
mIsRootNode = isRootNode;
|
||||
mAllocator = allocator;
|
||||
if (DEBUG)
|
||||
mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace());
|
||||
}
|
||||
|
||||
public UiObject parent() {
|
||||
return new UiObject(getParent().getInfo());
|
||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator) {
|
||||
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) {
|
||||
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) {
|
||||
@@ -110,6 +149,31 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
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) {
|
||||
Bundle bundle = new Bundle();
|
||||
for (ActionArgument arg : arguments) {
|
||||
@@ -263,7 +327,8 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
||||
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));
|
||||
if (compat != null)
|
||||
uiObjects.add(new UiObject(compat.getInfo(), allocator));
|
||||
}
|
||||
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);
|
||||
if (node != null)
|
||||
return node;
|
||||
else
|
||||
child.recycle();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -77,8 +77,6 @@ public abstract class FilterAction extends SimpleAction {
|
||||
UiObject nodeInfo = findAccessibilityNodeInfosByBounds(child);
|
||||
if (nodeInfo != null)
|
||||
return nodeInfo;
|
||||
else
|
||||
child.recycle();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -34,24 +34,29 @@ public class ScrollAction extends SimpleAction {
|
||||
|
||||
private List<UiObject> findScrollableNodes(UiObject root) {
|
||||
List<UiObject> list = new ArrayList<>();
|
||||
findScrollableNodes(root, list);
|
||||
if (root != null) {
|
||||
findScrollableNodes(root, list);
|
||||
if (root.isScrollable()) {
|
||||
list.add(root);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static boolean findScrollableNodes(UiObject node, List<UiObject> list) {
|
||||
private static void findScrollableNodes(UiObject node, List<UiObject> list) {
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
if (node.isScrollable()) {
|
||||
list.add(node);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < node.getChildCount(); i++) {
|
||||
UiObject child = node.child(i);
|
||||
if (child == null)
|
||||
continue;
|
||||
if (!findScrollableNodes(child, list))
|
||||
findScrollableNodes(child, list);
|
||||
if (child.isScrollable()) {
|
||||
list.add(child);
|
||||
} else {
|
||||
child.recycle();
|
||||
}
|
||||
}
|
||||
return node.isScrollable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import android.util.Log;
|
||||
|
||||
import com.stardust.automator.UiObject;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/1/27.
|
||||
*/
|
||||
@@ -15,6 +18,7 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
private int mScrollAction;
|
||||
private UiObject mMaxScrollableNode;
|
||||
private UiObject mRootNode;
|
||||
private Set<UiObject> mRecycledMaxUiObjects = new HashSet<>();
|
||||
|
||||
public ScrollMaxAction(int scrollAction) {
|
||||
mScrollAction = scrollAction;
|
||||
@@ -35,6 +39,7 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
mMaxScrollableNode.recycle();
|
||||
}
|
||||
mMaxScrollableNode = mRootNode = null;
|
||||
mRecycledMaxUiObjects.clear();
|
||||
}
|
||||
|
||||
private void findMaxScrollableNodeInfo(UiObject nodeInfo) {
|
||||
@@ -44,8 +49,10 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
if (mMaxScrollableNode == null) {
|
||||
mMaxScrollableNode = nodeInfo;
|
||||
} else if (getAreaInScreen(mMaxScrollableNode) < getAreaInScreen(nodeInfo)) {
|
||||
if (mMaxScrollableNode != mRootNode)
|
||||
if (mMaxScrollableNode != mRootNode) {
|
||||
mRecycledMaxUiObjects.add(mMaxScrollableNode);
|
||||
mMaxScrollableNode.recycle();
|
||||
}
|
||||
mMaxScrollableNode = nodeInfo;
|
||||
}
|
||||
}
|
||||
@@ -53,7 +60,7 @@ public class ScrollMaxAction extends SimpleAction {
|
||||
UiObject child = nodeInfo.child(i);
|
||||
if (child != null) {
|
||||
findMaxScrollableNodeInfo(child);
|
||||
if (mMaxScrollableNode != child) {
|
||||
if (mMaxScrollableNode != child && !mRecycledMaxUiObjects.contains(child)) {
|
||||
child.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ public class SearchUpTargetAction extends SearchTargetAction {
|
||||
while (node != null && !mAble.isAble(node)) {
|
||||
i++;
|
||||
if (i > LOOP_MAX) {
|
||||
node.recycle();
|
||||
return null;
|
||||
}
|
||||
node = node.parent();
|
||||
|
||||
@@ -79,7 +79,7 @@ public class SimpleActionPerformHost implements AccessibilityDelegate {
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "perform simpleAction: " + mSimpleAction);
|
||||
if (mSimpleAction.perform(new UiObject(mRoot))) {
|
||||
if (mSimpleAction.perform(UiObject.createRoot(mRoot))) {
|
||||
mSimpleAction.setResult(true);
|
||||
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;
|
||||
}
|
||||
|
||||
private AccessibilityNodeInfo add(@Nullable AccessibilityNodeInfo nodeInfo) {
|
||||
public AccessibilityNodeInfo add(@Nullable AccessibilityNodeInfo nodeInfo) {
|
||||
String stackTrace = DEBUG ? Arrays.toString(Thread.currentThread().getStackTrace()) : null;
|
||||
if (nodeInfo != null)
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user