This commit is contained in:
hyb1996
2017-05-02 11:27:04 +08:00
parent 0d39afccb2
commit 68706fbd98
71 changed files with 759 additions and 514 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}
}