optimize: code generation
This commit is contained in:
@@ -16,7 +16,8 @@ import com.bignerdranch.expandablerecyclerview.ChildViewHolder;
|
|||||||
import com.bignerdranch.expandablerecyclerview.ExpandableRecyclerAdapter;
|
import com.bignerdranch.expandablerecyclerview.ExpandableRecyclerAdapter;
|
||||||
import com.bignerdranch.expandablerecyclerview.ParentViewHolder;
|
import com.bignerdranch.expandablerecyclerview.ParentViewHolder;
|
||||||
import com.bignerdranch.expandablerecyclerview.model.Parent;
|
import com.bignerdranch.expandablerecyclerview.model.Parent;
|
||||||
import com.stardust.autojs.codegeneration.UiSelectorGenerator;
|
import com.stardust.app.DialogUtils;
|
||||||
|
import com.stardust.autojs.codegeneration.CodeGenerator;
|
||||||
import com.stardust.scriptdroid.R;
|
import com.stardust.scriptdroid.R;
|
||||||
import com.stardust.scriptdroid.ui.widget.CheckBoxCompat;
|
import com.stardust.scriptdroid.ui.widget.CheckBoxCompat;
|
||||||
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
|
||||||
@@ -66,39 +67,39 @@ public class CodeGenerateDialog extends ThemeColorMaterialDialogBuilder {
|
|||||||
super(context);
|
super(context);
|
||||||
mRootNode = rootNode;
|
mRootNode = rootNode;
|
||||||
mTargetNode = targetNode;
|
mTargetNode = targetNode;
|
||||||
positiveText(R.string.text_generate_and_copy);
|
positiveText(R.string.text_generate);
|
||||||
neutralText(R.string.text_generate_and_open_editor);
|
negativeText(R.string.text_cancel);
|
||||||
onPositive(((dialog, which) -> generateCodeAndCopy()));
|
onPositive(((dialog, which) -> generateCodeAndShow()));
|
||||||
onNeutral(((dialog, which) -> generateCodeAndOpenEditor()));
|
|
||||||
setupViews();
|
setupViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateCodeAndCopy() {
|
private void generateCodeAndShow() {
|
||||||
String code = generateCode();
|
String code = generateCode();
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
Toast.makeText(getContext(), R.string.text_generate_fail, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getContext(), R.string.text_generate_fail, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ClipboardUtil.setClip(getContext(), code);
|
DialogUtils.showDialog(new ThemeColorMaterialDialogBuilder(getContext())
|
||||||
Toast.makeText(getContext(), R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
|
.title(R.string.text_generated_code)
|
||||||
|
.content(code)
|
||||||
|
.positiveText(R.string.text_copy)
|
||||||
|
.onPositive(((dialog, which) -> ClipboardUtil.setClip(getContext(), code)))
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateCodeAndOpenEditor() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateCode() {
|
private String generateCode() {
|
||||||
UiSelectorGenerator generator = new UiSelectorGenerator(mRootNode, mTargetNode);
|
CodeGenerator generator = new CodeGenerator(mRootNode, mTargetNode);
|
||||||
OptionGroup settings = getOptionGroup(R.string.text_options);
|
OptionGroup settings = getOptionGroup(R.string.text_options);
|
||||||
generator.setUsingId(settings.getOption(R.string.text_using_id_selector).checked);
|
generator.setUsingId(settings.getOption(R.string.text_using_id_selector).checked);
|
||||||
generator.setUsingText(settings.getOption(R.string.text_using_text_selector).checked);
|
generator.setUsingText(settings.getOption(R.string.text_using_text_selector).checked);
|
||||||
generator.setUsingDesc(settings.getOption(R.string.text_using_desc_selector).checked);
|
generator.setUsingDesc(settings.getOption(R.string.text_using_desc_selector).checked);
|
||||||
generator.setSearchMode(getSearchMode());
|
generator.setSearchMode(getSearchMode());
|
||||||
setAction(generator);
|
setAction(generator);
|
||||||
return generator.generate();
|
return generator.generateCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAction(UiSelectorGenerator generator) {
|
private void setAction(CodeGenerator generator) {
|
||||||
OptionGroup action = getOptionGroup(R.string.text_action);
|
OptionGroup action = getOptionGroup(R.string.text_action);
|
||||||
if (action.getOption(R.string.text_click).checked) {
|
if (action.getOption(R.string.text_click).checked) {
|
||||||
generator.setAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
|
generator.setAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
|
||||||
@@ -117,18 +118,18 @@ public class CodeGenerateDialog extends ThemeColorMaterialDialogBuilder {
|
|||||||
private int getSearchMode() {
|
private int getSearchMode() {
|
||||||
OptionGroup selectMode = getOptionGroup(R.string.text_select);
|
OptionGroup selectMode = getOptionGroup(R.string.text_select);
|
||||||
if (selectMode.getOption(R.string.text_find_one).checked) {
|
if (selectMode.getOption(R.string.text_find_one).checked) {
|
||||||
return UiSelectorGenerator.FIND_ONE;
|
return CodeGenerator.FIND_ONE;
|
||||||
}
|
}
|
||||||
if (selectMode.getOption(R.string.text_until_find).checked) {
|
if (selectMode.getOption(R.string.text_until_find).checked) {
|
||||||
return UiSelectorGenerator.UNTIL_FIND;
|
return CodeGenerator.UNTIL_FIND;
|
||||||
}
|
}
|
||||||
if (selectMode.getOption(R.string.text_wait_for).checked) {
|
if (selectMode.getOption(R.string.text_wait_for).checked) {
|
||||||
return UiSelectorGenerator.WAIT_FOR;
|
return CodeGenerator.WAIT_FOR;
|
||||||
}
|
}
|
||||||
if (selectMode.getOption(R.string.text_wait_for).checked) {
|
if (selectMode.getOption(R.string.text_wait_for).checked) {
|
||||||
return UiSelectorGenerator.EXISTS;
|
return CodeGenerator.EXISTS;
|
||||||
}
|
}
|
||||||
return UiSelectorGenerator.FIND_ONE;
|
return CodeGenerator.FIND_ONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupViews() {
|
private void setupViews() {
|
||||||
|
|||||||
@@ -299,7 +299,7 @@
|
|||||||
<string name="text_using_id_selector">使用id选择</string>
|
<string name="text_using_id_selector">使用id选择</string>
|
||||||
<string name="text_using_text_selector">使用文本选择(text)</string>
|
<string name="text_using_text_selector">使用文本选择(text)</string>
|
||||||
<string name="text_using_desc_selector">使用描述选择(desc)</string>
|
<string name="text_using_desc_selector">使用描述选择(desc)</string>
|
||||||
<string name="text_generate_and_copy">生成并复制</string>
|
<string name="text_generate">生成</string>
|
||||||
<string name="text_generate_and_open_editor">生成并打开编辑器</string>
|
<string name="text_generate_and_open_editor">生成并打开编辑器</string>
|
||||||
<string name="text_generate_fail">生成失败了o(╥﹏╥)o</string>
|
<string name="text_generate_fail">生成失败了o(╥﹏╥)o</string>
|
||||||
<string name="key_documentation_source">key_documentation_source</string>
|
<string name="key_documentation_source">key_documentation_source</string>
|
||||||
@@ -326,4 +326,6 @@
|
|||||||
<string name="text_apk_builder_plugin_unavailable">打包插件不可用</string>
|
<string name="text_apk_builder_plugin_unavailable">打包插件不可用</string>
|
||||||
<string name="text_detail">详情</string>
|
<string name="text_detail">详情</string>
|
||||||
<string name="text_open">打开</string>
|
<string name="text_open">打开</string>
|
||||||
|
<string name="text_generated_code">生成结果</string>
|
||||||
|
<string name="text_copy">复制</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
package com.stardust.autojs.codegeneration;
|
||||||
|
|
||||||
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
|
|
||||||
|
import com.stardust.automator.UiGlobalSelector;
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
|
import com.stardust.view.accessibility.NodeInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Stardust on 2017/12/7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class CodeGenerator {
|
||||||
|
|
||||||
|
public static final int UNTIL_FIND = 0;
|
||||||
|
public static final int FIND_ONE = 1;
|
||||||
|
public static final int WAIT_FOR = 2;
|
||||||
|
public static final int EXISTS = 3;
|
||||||
|
|
||||||
|
private ReadOnlyUiObject mRoot;
|
||||||
|
private ReadOnlyUiObject mTarget;
|
||||||
|
private boolean mUsingId = true;
|
||||||
|
private boolean mUsingDesc = true;
|
||||||
|
private boolean mUsingText = true;
|
||||||
|
private int mSearchMode = FIND_ONE;
|
||||||
|
private int mAction = -1;
|
||||||
|
|
||||||
|
public CodeGenerator(NodeInfo root, NodeInfo target) {
|
||||||
|
this(new ReadOnlyUiObject(root), new ReadOnlyUiObject(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CodeGenerator(ReadOnlyUiObject root, ReadOnlyUiObject target) {
|
||||||
|
mRoot = root;
|
||||||
|
mTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setUsingId(boolean usingId) {
|
||||||
|
mUsingId = usingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsingDesc(boolean usingDesc) {
|
||||||
|
mUsingDesc = usingDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsingText(boolean usingText) {
|
||||||
|
mUsingText = usingText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchMode(int searchMode) {
|
||||||
|
mSearchMode = searchMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(int action) {
|
||||||
|
mAction = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateCode() {
|
||||||
|
UiObject collection = getCollectionParent(mTarget);
|
||||||
|
if (collection != null) {
|
||||||
|
return generateCodeForCollectionChild(collection, mTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
UiSelectorGenerator generator = new UiSelectorGenerator(mRoot, mTarget);
|
||||||
|
generator.setSearchMode(mSearchMode);
|
||||||
|
generator.setUsingDesc(mUsingDesc);
|
||||||
|
generator.setUsingId(mUsingId);
|
||||||
|
generator.setUsingText(mUsingText);
|
||||||
|
String selector = generateCode(generator, mRoot, mTarget, 2, 2);
|
||||||
|
if (selector == null)
|
||||||
|
return null;
|
||||||
|
return generateAction(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateCode(UiSelectorGenerator generator, UiObject root, UiObject target, int maxParentLevel, int maxChildrenLevel) {
|
||||||
|
String selector = generator.generateSelectorCode();
|
||||||
|
if (selector != null) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (maxChildrenLevel > 0) {
|
||||||
|
for (int i = 0; i < target.childCount(); i++) {
|
||||||
|
UiObject child = target.child(i);
|
||||||
|
if (child == null)
|
||||||
|
continue;
|
||||||
|
String childCode = generateCode(root, child, 0, maxChildrenLevel - 1);
|
||||||
|
if (childCode != null) {
|
||||||
|
return childCode + ".parent()";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxParentLevel > 0 && target.parent() != null) {
|
||||||
|
int index = target.indexInParent();
|
||||||
|
if (index > 0) {
|
||||||
|
String parentCode = generateCode(root, target.parent(), maxParentLevel - 1, 0);
|
||||||
|
if (parentCode != null) {
|
||||||
|
return parentCode + "child(" + index + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String generateCode(UiObject root, UiObject target, int maxParentLevel, int maxChildrenLevel) {
|
||||||
|
UiSelectorGenerator generator = new UiSelectorGenerator(root, target);
|
||||||
|
generator.setUsingId(mUsingId);
|
||||||
|
return generateCode(generator, root, target, maxParentLevel, maxChildrenLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateAction(String selector) {
|
||||||
|
if (selector == null)
|
||||||
|
return null;
|
||||||
|
if (mSearchMode == WAIT_FOR) {
|
||||||
|
return selector + ".waitFor()";
|
||||||
|
}
|
||||||
|
if (mSearchMode == EXISTS) {
|
||||||
|
return "if(" + selector + ".exists()){\n \n}";
|
||||||
|
}
|
||||||
|
String action = getAction();
|
||||||
|
if (action.isEmpty()) {
|
||||||
|
return selector;
|
||||||
|
} else {
|
||||||
|
return selector + "." + action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAction() {
|
||||||
|
switch (mAction) {
|
||||||
|
case AccessibilityNodeInfoCompat.ACTION_CLICK:
|
||||||
|
return "click()";
|
||||||
|
case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
|
||||||
|
return "longClick()";
|
||||||
|
|
||||||
|
case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
|
||||||
|
return "scrollBackward()";
|
||||||
|
|
||||||
|
case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
|
||||||
|
return "scrollForward()";
|
||||||
|
|
||||||
|
case AccessibilityNodeInfoCompat.ACTION_SET_TEXT:
|
||||||
|
return "setText(\"\")";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateCodeForCollectionChild(UiObject collection, UiObject target) {
|
||||||
|
UiObject parent = target.parent();
|
||||||
|
if (parent == null)
|
||||||
|
return null;
|
||||||
|
UiObject collectionItem = null;
|
||||||
|
for (int i = 0; i < collection.childCount(); i++) {
|
||||||
|
if (inherits(collection.child(i), target)) {
|
||||||
|
collectionItem = collection.child(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (collectionItem == null)
|
||||||
|
return null;
|
||||||
|
String collectionCode = generateCode(mRoot, collection, 2, 0);
|
||||||
|
if (collectionCode == null)
|
||||||
|
return null;
|
||||||
|
String itemCode = generateCode(collectionItem, target, 1, 2);
|
||||||
|
if (itemCode == null)
|
||||||
|
return null;
|
||||||
|
return collectionCode + ".findOne().children().forEach(child => {\n"
|
||||||
|
+ "var target = child.findOne(" + itemCode + ");\n"
|
||||||
|
+ "target." + getAction() + ";\n"
|
||||||
|
+ "});";
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean inherits(UiObject root, UiObject target) {
|
||||||
|
for (int i = 0; i < root.childCount(); i++) {
|
||||||
|
UiObject child = root.child(i);
|
||||||
|
if (child != null) {
|
||||||
|
if (child.equals(target) || inherits(child, target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UiObject getCollectionParent(UiObject target) {
|
||||||
|
UiObject parent = target.parent();
|
||||||
|
while (parent != null) {
|
||||||
|
if (parent.rowCount() > 0 || parent.columnCount() > 0) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
parent = parent.parent();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@ import android.support.annotation.Nullable;
|
|||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
|
|
||||||
import com.stardust.automator.UiObject;
|
import com.stardust.automator.UiObject;
|
||||||
import com.stardust.automator.UiObjectCollection;
|
|
||||||
import com.stardust.view.accessibility.NodeInfo;
|
import com.stardust.view.accessibility.NodeInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,19 +15,27 @@ import com.stardust.view.accessibility.NodeInfo;
|
|||||||
public class ReadOnlyUiObject extends UiObject {
|
public class ReadOnlyUiObject extends UiObject {
|
||||||
|
|
||||||
private NodeInfo mNodeInfo;
|
private NodeInfo mNodeInfo;
|
||||||
private boolean mUsingId;
|
|
||||||
private boolean mUsingText;
|
|
||||||
private boolean mUsingDesc;
|
|
||||||
|
|
||||||
public ReadOnlyUiObject(NodeInfo info) {
|
public ReadOnlyUiObject(NodeInfo info) {
|
||||||
super(info, info.depth);
|
super(info, info.depth, -1);
|
||||||
|
mNodeInfo = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReadOnlyUiObject(NodeInfo info, int indexInParent) {
|
||||||
|
super(info, info.depth, indexInParent);
|
||||||
mNodeInfo = info;
|
mNodeInfo = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public UiObject child(int i) {
|
public UiObject child(int i) {
|
||||||
return new ReadOnlyUiObject(mNodeInfo.getChildren().get(i));
|
return new ReadOnlyUiObject(mNodeInfo.getChildren().get(i), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public UiObject parent() {
|
||||||
|
return mNodeInfo.parent == null ? null : new ReadOnlyUiObject(mNodeInfo.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -189,6 +196,82 @@ public class ReadOnlyUiObject extends UiObject {
|
|||||||
return mNodeInfo.scrollable;
|
return mNodeInfo.scrollable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCheckable() {
|
||||||
|
return checkable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChecked() {
|
||||||
|
return checked();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFocusable() {
|
||||||
|
return focusable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFocused() {
|
||||||
|
return focused();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVisibleToUser() {
|
||||||
|
return visibleToUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccessibilityFocused() {
|
||||||
|
return accessibilityFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSelected() {
|
||||||
|
return selected();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClickable() {
|
||||||
|
return clickable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLongClickable() {
|
||||||
|
return longClickable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPassword() {
|
||||||
|
return password();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isScrollable() {
|
||||||
|
return scrollable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isContextClickable() {
|
||||||
|
return mNodeInfo.contextClickable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDismissable() {
|
||||||
|
return mNodeInfo.dismissable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEditable() {
|
||||||
|
return mNodeInfo.editable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int row() {
|
public int row() {
|
||||||
return mNodeInfo.row;
|
return mNodeInfo.row;
|
||||||
@@ -223,4 +306,27 @@ public class ReadOnlyUiObject extends UiObject {
|
|||||||
public void recycle() {
|
public void recycle() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
|
||||||
|
ReadOnlyUiObject that = (ReadOnlyUiObject) o;
|
||||||
|
|
||||||
|
return mNodeInfo.equals(that.mNodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + mNodeInfo.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mNodeInfo.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,81 @@
|
|||||||
package com.stardust.autojs.codegeneration;
|
package com.stardust.autojs.codegeneration;
|
||||||
|
|
||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
|
||||||
|
|
||||||
import com.stardust.automator.UiGlobalSelector;
|
import com.stardust.automator.UiGlobalSelector;
|
||||||
|
import com.stardust.automator.UiObject;
|
||||||
import com.stardust.util.Consumer;
|
import com.stardust.util.Consumer;
|
||||||
import com.stardust.view.accessibility.NodeInfo;
|
|
||||||
|
import static com.stardust.autojs.codegeneration.CodeGenerator.FIND_ONE;
|
||||||
|
import static com.stardust.autojs.codegeneration.CodeGenerator.UNTIL_FIND;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/8/4.
|
* Created by Stardust on 2017/12/7.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class UiSelectorGenerator {
|
public class UiSelectorGenerator {
|
||||||
|
|
||||||
|
private UiObject mRoot;
|
||||||
public static final int UNTIL_FIND = 0;
|
private UiObject mTarget;
|
||||||
public static final int FIND_ONE = 1;
|
|
||||||
public static final int WAIT_FOR = 2;
|
|
||||||
public static final int EXISTS = 3;
|
|
||||||
|
|
||||||
private ReadOnlyUiObject mRoot;
|
|
||||||
private ReadOnlyUiObject mTarget;
|
|
||||||
private boolean mUsingId = true;
|
private boolean mUsingId = true;
|
||||||
private boolean mUsingDesc = true;
|
private boolean mUsingDesc = true;
|
||||||
private boolean mUsingText = true;
|
private boolean mUsingText = true;
|
||||||
private UiGlobalSelector mUiGlobalSelector;
|
|
||||||
private int mSearchMode = FIND_ONE;
|
private int mSearchMode = FIND_ONE;
|
||||||
private int mAction = -1;
|
|
||||||
|
|
||||||
public UiSelectorGenerator(NodeInfo root, NodeInfo target) {
|
public UiSelectorGenerator(UiObject root, UiObject target) {
|
||||||
this(new ReadOnlyUiObject(root), new ReadOnlyUiObject(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
public UiSelectorGenerator(ReadOnlyUiObject root, ReadOnlyUiObject target) {
|
|
||||||
mRoot = root;
|
mRoot = root;
|
||||||
mTarget = target;
|
mTarget = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSearchMode(int searchMode) {
|
public UiGlobalSelector generateSelector() {
|
||||||
mSearchMode = searchMode;
|
UiGlobalSelector selector = new UiGlobalSelector();
|
||||||
|
if (mUsingId &&
|
||||||
|
tryWithStringCondition(selector, mTarget.id(), selector::id)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tryWithStringCondition(selector, mTarget.className(), selector::className)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mUsingText &&
|
||||||
|
tryWithStringCondition(selector, mTarget.text(), selector::text)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mUsingDesc &&
|
||||||
|
tryWithStringCondition(selector, mTarget.desc(), selector::desc)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mTarget.scrollable() && tryWithBooleanCondition(selector, mTarget.scrollable(), selector::scrollable)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mTarget.clickable() && tryWithBooleanCondition(selector, mTarget.clickable(), selector::clickable)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mTarget.selected() && tryWithBooleanCondition(selector, mTarget.selected(), selector::selected)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mTarget.checkable() && tryWithBooleanCondition(selector, mTarget.checkable(), selector::checkable)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mTarget.checked() && tryWithBooleanCondition(selector, mTarget.checked(), selector::checked)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (mTarget.longClickable() && tryWithBooleanCondition(selector, mTarget.longClickable(), selector::longClickable)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
if (tryWithIntCondition(selector, mTarget.depth(), selector::depth)) {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(int action) {
|
public String generateSelectorCode() {
|
||||||
mAction = action;
|
UiGlobalSelector selector = generateSelector();
|
||||||
|
if (selector == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return selector + (mSearchMode == FIND_ONE ? ".findOne()" : ".untilFind()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setUsingId(boolean usingId) {
|
public void setUsingId(boolean usingId) {
|
||||||
mUsingId = usingId;
|
mUsingId = usingId;
|
||||||
}
|
}
|
||||||
@@ -56,94 +88,37 @@ public class UiSelectorGenerator {
|
|||||||
mUsingText = usingText;
|
mUsingText = usingText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSearchMode(int searchMode) {
|
||||||
|
mSearchMode = searchMode;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean tryWithStringCondition(String name, String value, Consumer<String> condition, StringBuilder code) {
|
private boolean tryWithBooleanCondition(UiGlobalSelector selector, boolean value, Consumer<Boolean> condition) {
|
||||||
if (value == null || value.isEmpty())
|
condition.accept(value);
|
||||||
|
return shouldStopGeneration(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean tryWithStringCondition(UiGlobalSelector selector, String value, Consumer<String> condition) {
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
code.append('.').append(name).append("(\"").append(value).append("\")");
|
}
|
||||||
condition.accept(value);
|
condition.accept(value);
|
||||||
return isConditionEnough();
|
return shouldStopGeneration(selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean tryWithIntCondition(String name, int value, Consumer<Integer> condition, StringBuilder code) {
|
private boolean shouldStopGeneration(UiGlobalSelector selector) {
|
||||||
code.append('.').append(name).append('(').append(value).append(')');
|
|
||||||
condition.accept(value);
|
|
||||||
return isConditionEnough();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConditionEnough() {
|
|
||||||
if (mSearchMode == UNTIL_FIND) {
|
if (mSearchMode == UNTIL_FIND) {
|
||||||
return !mUiGlobalSelector.findAndReturnList(mRoot).isEmpty();
|
return !selector.findAndReturnList(mRoot).isEmpty();
|
||||||
} else {
|
} else {
|
||||||
return mUiGlobalSelector.findAndReturnList(mRoot).size() == 1;
|
return selector.findAndReturnList(mRoot).size() == 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generate() {
|
private boolean tryWithIntCondition(UiGlobalSelector selector, int value, Consumer<Integer> condition) {
|
||||||
String selector = generateSelector();
|
condition.accept(value);
|
||||||
if (selector == null) {
|
return shouldStopGeneration(selector);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
//remove '.'
|
|
||||||
selector = selector.substring(1);
|
|
||||||
if (mSearchMode == WAIT_FOR) {
|
|
||||||
return selector + ".waitFor()";
|
|
||||||
}
|
|
||||||
if (mSearchMode == EXISTS) {
|
|
||||||
return "if(" + selector + ".exists()){\n \n}";
|
|
||||||
}
|
|
||||||
String action = getAction();
|
|
||||||
if (action == null) {
|
|
||||||
return selector;
|
|
||||||
} else {
|
|
||||||
return selector + action;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getAction() {
|
|
||||||
switch (mAction) {
|
|
||||||
case AccessibilityNodeInfoCompat.ACTION_CLICK:
|
|
||||||
return ".click()";
|
|
||||||
case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
|
|
||||||
return ".longClick()";
|
|
||||||
|
|
||||||
case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
|
|
||||||
return ".scrollBackward()";
|
|
||||||
|
|
||||||
case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
|
|
||||||
return ".scrollForward()";
|
|
||||||
|
|
||||||
case AccessibilityNodeInfoCompat.ACTION_SET_TEXT:
|
|
||||||
return ".setText(\"\")";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateSelector() {
|
|
||||||
mUiGlobalSelector = new UiGlobalSelector();
|
|
||||||
StringBuilder code = new StringBuilder();
|
|
||||||
if (mUsingId &&
|
|
||||||
tryWithStringCondition("id", mTarget.id(), mUiGlobalSelector::id, code)) {
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
if (tryWithIntCondition("depth", mTarget.depth(), mUiGlobalSelector::depth, code)) {
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
if (tryWithStringCondition("className", mTarget.className(), mUiGlobalSelector::className, code)) {
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUsingText &&
|
|
||||||
tryWithStringCondition("text", mTarget.text(), mUiGlobalSelector::text, code)) {
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUsingDesc &&
|
|
||||||
tryWithStringCondition("desc", mTarget.desc(), mUiGlobalSelector::desc, code)) {
|
|
||||||
return code.toString();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,6 +178,11 @@ public class UiGlobalSelector {
|
|||||||
protected boolean isIncluded(UiObject nodeInfo) {
|
protected boolean isIncluded(UiObject nodeInfo) {
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && nodeInfo.getDrawingOrder() == order;
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && nodeInfo.getDrawingOrder() == order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "drawingOrder(" + order + ")";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -430,5 +435,13 @@ public class UiGlobalSelector {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
for (ListFilter filter : mFilters) {
|
||||||
|
str.append(filter.toString()).append(".");
|
||||||
|
}
|
||||||
|
str.deleteCharAt(str.length() - 1);
|
||||||
|
return str.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,37 +37,39 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
|
|
||||||
|
|
||||||
public static UiObject createRoot(AccessibilityNodeInfo root) {
|
public static UiObject createRoot(AccessibilityNodeInfo root) {
|
||||||
return new UiObject(root, null, 0);
|
return new UiObject(root, null, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UiObject createRoot(AccessibilityNodeInfo root, AccessibilityNodeInfoAllocator allocator) {
|
public static UiObject createRoot(AccessibilityNodeInfo root, AccessibilityNodeInfoAllocator allocator) {
|
||||||
return new UiObject(root, allocator, 0);
|
return new UiObject(root, allocator, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AccessibilityNodeInfoAllocator mAllocator = null;
|
private AccessibilityNodeInfoAllocator mAllocator = null;
|
||||||
private String mStackTrace = "";
|
private String mStackTrace = "";
|
||||||
private int mDepth = 0;
|
private int mDepth = 0;
|
||||||
|
private final int mIndexInParent;
|
||||||
|
|
||||||
public UiObject(Object info) {
|
public UiObject(Object info) {
|
||||||
this(info, 0);
|
this(info, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, int depth) {
|
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, int depth, int indexInParent) {
|
||||||
super(info);
|
super(info);
|
||||||
mDepth = depth;
|
mDepth = depth;
|
||||||
mAllocator = allocator;
|
mAllocator = allocator;
|
||||||
|
mIndexInParent = indexInParent;
|
||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace());
|
mStackTrace = Arrays.toString(Thread.currentThread().getStackTrace());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator) {
|
public UiObject(Object info, AccessibilityNodeInfoAllocator allocator, int indexInParent) {
|
||||||
this(info, allocator, 0);
|
this(info, allocator, 0, indexInParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UiObject(Object info, int depth) {
|
public UiObject(Object info, int depth, int indexInParent) {
|
||||||
this(info, null, depth);
|
this(info, null, depth, indexInParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -76,7 +78,7 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
AccessibilityNodeInfoCompat parent = super.getParent();
|
AccessibilityNodeInfoCompat parent = super.getParent();
|
||||||
if (parent == null)
|
if (parent == null)
|
||||||
return null;
|
return null;
|
||||||
return new UiObject(parent.getInfo(), mDepth - 1);
|
return new UiObject(parent.getInfo(), mDepth - 1, -1);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
// FIXME: 2017/5/5
|
// FIXME: 2017/5/5
|
||||||
return null;
|
return null;
|
||||||
@@ -89,13 +91,17 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
AccessibilityNodeInfoCompat child = super.getChild(i);
|
AccessibilityNodeInfoCompat child = super.getChild(i);
|
||||||
if (child == null)
|
if (child == null)
|
||||||
return null;
|
return null;
|
||||||
return new UiObject(child.getInfo(), mDepth + 1);
|
return new UiObject(child.getInfo(), mDepth + 1, i);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
// FIXME: 2017/5/5
|
// FIXME: 2017/5/5
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int indexInParent() {
|
||||||
|
return mIndexInParent;
|
||||||
|
}
|
||||||
|
|
||||||
public UiObjectCollection find(UiGlobalSelector selector) {
|
public UiObjectCollection find(UiGlobalSelector selector) {
|
||||||
return selector.findOf(this);
|
return selector.findOf(this);
|
||||||
}
|
}
|
||||||
@@ -105,11 +111,11 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public UiObjectCollection children() {
|
public UiObjectCollection children() {
|
||||||
ArrayList<AccessibilityNodeInfoCompat> list = new ArrayList<>(getChildCount());
|
ArrayList<UiObject> list = new ArrayList<>(getChildCount());
|
||||||
for (int i = 0; i < getChildCount(); i++) {
|
for (int i = 0; i < getChildCount(); i++) {
|
||||||
list.add(getChild(i));
|
list.add(child(i));
|
||||||
}
|
}
|
||||||
return UiObjectCollection.ofCompat(list);
|
return UiObjectCollection.of(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int childCount() {
|
public int childCount() {
|
||||||
@@ -428,20 +434,6 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
return new UiGlobalSelector().id(viewId).findAndReturnList(this);
|
return new UiGlobalSelector().id(viewId).findAndReturnList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<UiObject> compatListToUiObjectList(List<AccessibilityNodeInfoCompat> compats, AccessibilityNodeInfoAllocator allocator) {
|
|
||||||
// FIXME: 2017/11/5 lost depth info
|
|
||||||
List<UiObject> uiObjects = new ArrayList<>(compats.size());
|
|
||||||
for (AccessibilityNodeInfoCompat compat : compats) {
|
|
||||||
if (compat != null)
|
|
||||||
uiObjects.add(new UiObject(compat.getInfo(), allocator));
|
|
||||||
}
|
|
||||||
return uiObjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<UiObject> compatListToUiObjectList(List<AccessibilityNodeInfoCompat> compats) {
|
|
||||||
return compatListToUiObjectList(compats, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recycle() {
|
public void recycle() {
|
||||||
try {
|
try {
|
||||||
@@ -451,4 +443,5 @@ public class UiObject extends AccessibilityNodeInfoCompat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ public class UiObjectCollection {
|
|||||||
|
|
||||||
public static final UiObjectCollection EMPTY = UiObjectCollection.of(Collections.<UiObject>emptyList());
|
public static final UiObjectCollection EMPTY = UiObjectCollection.of(Collections.<UiObject>emptyList());
|
||||||
|
|
||||||
public static UiObjectCollection ofCompat(List<AccessibilityNodeInfoCompat> list) {
|
|
||||||
return new UiObjectCollection(UiObject.compatListToUiObjectList(list));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UiObjectCollection of(List<UiObject> list) {
|
public static UiObjectCollection of(List<UiObject> list) {
|
||||||
return new UiObjectCollection(list);
|
return new UiObjectCollection(list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isCheckable();
|
return node.isCheckable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "checkable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier CHECKED = new BooleanSupplier() {
|
public static final BooleanSupplier CHECKED = new BooleanSupplier() {
|
||||||
@@ -50,6 +55,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isChecked();
|
return node.isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "checked";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier FOCUSABLE = new BooleanSupplier() {
|
public static final BooleanSupplier FOCUSABLE = new BooleanSupplier() {
|
||||||
@@ -58,6 +68,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isFocusable();
|
return node.isFocusable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "focusable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier FOCUSED = new BooleanSupplier() {
|
public static final BooleanSupplier FOCUSED = new BooleanSupplier() {
|
||||||
@@ -66,6 +81,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isFocused();
|
return node.isFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "focused";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier VISIBLE_TO_USER = new BooleanSupplier() {
|
public static final BooleanSupplier VISIBLE_TO_USER = new BooleanSupplier() {
|
||||||
@@ -74,6 +94,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isVisibleToUser();
|
return node.isVisibleToUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "visibleToUser";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier ACCESSIBILITY_FOCUSED = new BooleanSupplier() {
|
public static final BooleanSupplier ACCESSIBILITY_FOCUSED = new BooleanSupplier() {
|
||||||
@@ -82,6 +107,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isAccessibilityFocused();
|
return node.isAccessibilityFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "accessibilityFocused";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier SELECTED = new BooleanSupplier() {
|
public static final BooleanSupplier SELECTED = new BooleanSupplier() {
|
||||||
@@ -90,6 +120,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isSelected();
|
return node.isSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "selected";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier CLICKABLE = new BooleanSupplier() {
|
public static final BooleanSupplier CLICKABLE = new BooleanSupplier() {
|
||||||
@@ -98,6 +133,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isClickable();
|
return node.isClickable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "clickable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier LONG_CLICKABLE = new BooleanSupplier() {
|
public static final BooleanSupplier LONG_CLICKABLE = new BooleanSupplier() {
|
||||||
@@ -106,6 +146,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isLongClickable();
|
return node.isLongClickable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "longClickable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier ENABLED = new BooleanSupplier() {
|
public static final BooleanSupplier ENABLED = new BooleanSupplier() {
|
||||||
@@ -114,6 +159,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isEnabled();
|
return node.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "enabled";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -123,6 +173,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isPassword();
|
return node.isPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "password";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier SCROLLABLE = new BooleanSupplier() {
|
public static final BooleanSupplier SCROLLABLE = new BooleanSupplier() {
|
||||||
@@ -131,6 +186,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isScrollable();
|
return node.isScrollable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "scrollable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier EDITABLE = new BooleanSupplier() {
|
public static final BooleanSupplier EDITABLE = new BooleanSupplier() {
|
||||||
@@ -139,6 +199,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isEditable();
|
return node.isEditable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "editable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
public static final BooleanSupplier CONTENT_INVALID = new BooleanSupplier() {
|
public static final BooleanSupplier CONTENT_INVALID = new BooleanSupplier() {
|
||||||
|
|
||||||
@@ -146,6 +211,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isContentInvalid();
|
return node.isContentInvalid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "contentInvalid";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier CONTEXT_CLICKABLE = new BooleanSupplier() {
|
public static final BooleanSupplier CONTEXT_CLICKABLE = new BooleanSupplier() {
|
||||||
@@ -155,6 +225,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isContextClickable();
|
return node.isContextClickable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "checkable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier MULTI_LINE = new BooleanSupplier() {
|
public static final BooleanSupplier MULTI_LINE = new BooleanSupplier() {
|
||||||
@@ -163,6 +238,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isMultiLine();
|
return node.isMultiLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "multiLine";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final BooleanSupplier DISMISSABLE = new BooleanSupplier() {
|
public static final BooleanSupplier DISMISSABLE = new BooleanSupplier() {
|
||||||
@@ -171,6 +251,11 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
public boolean get(UiObject node) {
|
public boolean get(UiObject node) {
|
||||||
return node.isDismissable();
|
return node.isDismissable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "dismissable";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private BooleanSupplier mBooleanSupplier;
|
private BooleanSupplier mBooleanSupplier;
|
||||||
@@ -186,4 +271,8 @@ public class BooleanFilter extends DfsFilter {
|
|||||||
return nodeInfo != null && mBooleanSupplier.get(nodeInfo) == mExceptedValue;
|
return nodeInfo != null && mBooleanSupplier.get(nodeInfo) == mExceptedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mBooleanSupplier.toString() + "(" + mExceptedValue + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import android.graphics.Rect;
|
|||||||
import com.stardust.automator.UiObject;
|
import com.stardust.automator.UiObject;
|
||||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on 2017/3/9.
|
* Created by Stardust on 2017/3/9.
|
||||||
*/
|
*/
|
||||||
@@ -33,4 +35,11 @@ public class BoundsFilter extends DfsFilter {
|
|||||||
return boundsInScreen.equals(mBounds);
|
return boundsInScreen.equals(mBounds);
|
||||||
return mBounds.contains(boundsInScreen);
|
return mBounds.contains(boundsInScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(Locale.getDefault(), "bounds%s(%d, %d, %d, %d)", mType == TYPE_EQUALS ? "" :
|
||||||
|
mType == TYPE_INSIDE ? "Inside" : "Contains",
|
||||||
|
mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public class ClassNameFilter {
|
|||||||
CharSequence charSequence = nodeInfo.getClassName();
|
CharSequence charSequence = nodeInfo.getClassName();
|
||||||
return charSequence == null ? null : charSequence.toString();
|
return charSequence == null ? null : charSequence.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "className";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ListFilter equals(String text) {
|
public static ListFilter equals(String text) {
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public class DescFilter {
|
|||||||
CharSequence charSequence = nodeInfo.getContentDescription();
|
CharSequence charSequence = nodeInfo.getContentDescription();
|
||||||
return charSequence == null ? null : charSequence.toString();
|
return charSequence == null ? null : charSequence.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "desc";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ListFilter equals(String text) {
|
public static ListFilter equals(String text) {
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ public class IdFilter extends ListFilter.Default {
|
|||||||
public String getKey(UiObject nodeInfo) {
|
public String getKey(UiObject nodeInfo) {
|
||||||
return nodeInfo.getViewIdResourceName();
|
return nodeInfo.getViewIdResourceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "id";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static StringEqualsFilter equals(String id) {
|
public static StringEqualsFilter equals(String id) {
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.depth();
|
return object.depth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "depth";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final IntProperty ROW = new IntProperty() {
|
public static final IntProperty ROW = new IntProperty() {
|
||||||
@@ -24,6 +29,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.row();
|
return object.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "row";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final IntProperty ROW_COUNT = new IntProperty() {
|
public static final IntProperty ROW_COUNT = new IntProperty() {
|
||||||
@@ -31,6 +41,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.rowCount();
|
return object.rowCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "rowCount";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final IntProperty ROW_SPAN = new IntProperty() {
|
public static final IntProperty ROW_SPAN = new IntProperty() {
|
||||||
@@ -38,6 +53,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.rowSpan();
|
return object.rowSpan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "rowSpan";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final IntProperty COLUMN = new IntProperty() {
|
public static final IntProperty COLUMN = new IntProperty() {
|
||||||
@@ -45,6 +65,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.column();
|
return object.column();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "column";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final IntProperty COLUMN_COUNT = new IntProperty() {
|
public static final IntProperty COLUMN_COUNT = new IntProperty() {
|
||||||
@@ -52,6 +77,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.columnCount();
|
return object.columnCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "columnCount";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final IntProperty COLUMN_SPAN = new IntProperty() {
|
public static final IntProperty COLUMN_SPAN = new IntProperty() {
|
||||||
@@ -59,6 +89,11 @@ public class IntFilter extends DfsFilter {
|
|||||||
public int get(UiObject object) {
|
public int get(UiObject object) {
|
||||||
return object.columnSpan();
|
return object.columnSpan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "columnSpan";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private IntProperty mIntProperty;
|
private IntProperty mIntProperty;
|
||||||
@@ -73,4 +108,9 @@ public class IntFilter extends DfsFilter {
|
|||||||
protected boolean isIncluded(UiObject nodeInfo) {
|
protected boolean isIncluded(UiObject nodeInfo) {
|
||||||
return mIntProperty.get(nodeInfo) == mValue;
|
return mIntProperty.get(nodeInfo) == mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mIntProperty.toString() + "(" + mValue + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ public class PackageNameFilter {
|
|||||||
CharSequence charSequence = nodeInfo.getPackageName();
|
CharSequence charSequence = nodeInfo.getPackageName();
|
||||||
return charSequence == null ? null : charSequence.toString();
|
return charSequence == null ? null : charSequence.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "packageName";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ListFilter equals(String text) {
|
public static ListFilter equals(String text) {
|
||||||
|
|||||||
@@ -21,4 +21,8 @@ public class StringContainsFilter extends DfsFilter {
|
|||||||
return key != null && key.contains(mContains);
|
return key != null && key.contains(mContains);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mKeyGetter.toString() + "Contains(\"" + mContains + "\")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,8 @@ public class StringEndsWithFilter extends DfsFilter {
|
|||||||
return key != null && key.endsWith(mSuffix);
|
return key != null && key.endsWith(mSuffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mKeyGetter.toString() + "EndsWith(\"" + mSuffix + "\")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,14 @@ public class StringEqualsFilter extends DfsFilter {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean isIncluded(UiObject nodeInfo) {
|
protected boolean isIncluded(UiObject nodeInfo) {
|
||||||
String key = mKeyGetter.getKey(nodeInfo);
|
String key = mKeyGetter.getKey(nodeInfo);
|
||||||
if(key != null){
|
if (key != null) {
|
||||||
return key.equals(mText);
|
return key.equals(mText);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mKeyGetter.toString() + "(\"" + mText + "\")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,8 @@ public class StringMatchesFilter extends DfsFilter {
|
|||||||
return key != null && key.matches(mRegex);
|
return key != null && key.matches(mRegex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mKeyGetter.toString() + "Matches(\"" + mRegex + "\")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,8 @@ public class StringStartsWithFilter extends DfsFilter {
|
|||||||
return key != null && key.startsWith(mPrefix);
|
return key != null && key.startsWith(mPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mKeyGetter.toString() + "StartsWith(\"" + mPrefix + "\")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ public class TextFilter extends ListFilter.Default {
|
|||||||
CharSequence charSequence = nodeInfo.getText();
|
CharSequence charSequence = nodeInfo.getText();
|
||||||
return charSequence == null ? null : charSequence.toString();
|
return charSequence == null ? null : charSequence.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "text";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ListFilter equals(String text) {
|
public static ListFilter equals(String text) {
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
|||||||
Log.v(TAG, "onAccessibilityEvent: " + event);
|
Log.v(TAG, "onAccessibilityEvent: " + event);
|
||||||
if (!containsAllEventTypes && !eventTypes.contains(event.getEventType()))
|
if (!containsAllEventTypes && !eventTypes.contains(event.getEventType()))
|
||||||
return;
|
return;
|
||||||
int type = event.getEventType();
|
AccessibilityNodeInfo root = super.getRootInActiveWindow();
|
||||||
if (type == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED || type == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
|
if (root != null) {
|
||||||
|| type == AccessibilityEvent.TYPE_VIEW_HOVER_EXIT) {
|
mFastRootInActiveWindow = root;
|
||||||
mFastRootInActiveWindow = super.getRootInActiveWindow();
|
Log.v(TAG, "root not null: " + event);
|
||||||
}
|
}
|
||||||
for (Map.Entry<Integer, AccessibilityDelegate> entry : mDelegates.entrySet()) {
|
for (Map.Entry<Integer, AccessibilityDelegate> entry : mDelegates.entrySet()) {
|
||||||
AccessibilityDelegate delegate = entry.getValue();
|
AccessibilityDelegate delegate = entry.getValue();
|
||||||
@@ -164,4 +164,5 @@ public class AccessibilityService extends android.accessibilityservice.Accessibi
|
|||||||
return stickOnKeyObserver;
|
return stickOnKeyObserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,23 +28,28 @@ public class LayoutInspector {
|
|||||||
Log.d(LOG_TAG, "captureCurrentWindow: service = null");
|
Log.d(LOG_TAG, "captureCurrentWindow: service = null");
|
||||||
mCapture = null;
|
mCapture = null;
|
||||||
} else {
|
} else {
|
||||||
final AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
final AccessibilityNodeInfo root = getRootInActiveWindow(service);
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
Log.d(LOG_TAG, "captureCurrentWindow: root = null");
|
Log.d(LOG_TAG, "captureCurrentWindow: root = null");
|
||||||
mCapture = null;
|
mCapture = null;
|
||||||
} else {
|
} else {
|
||||||
mExecutor.execute(new Runnable() {
|
mExecutor.execute(() -> {
|
||||||
@Override
|
mDumping = true;
|
||||||
public void run() {
|
mCapture = NodeInfo.capture(root);
|
||||||
mDumping = true;
|
mDumping = false;
|
||||||
mCapture = NodeInfo.capture(root);
|
|
||||||
mDumping = false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AccessibilityNodeInfo getRootInActiveWindow(AccessibilityService service) {
|
||||||
|
AccessibilityNodeInfo root = service.getRootInActiveWindow();
|
||||||
|
if (root == null)
|
||||||
|
return service.fastRootInActiveWindow();
|
||||||
|
return root;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||||
private void refreshChildList(AccessibilityNodeInfo root) {
|
private void refreshChildList(AccessibilityNodeInfo root) {
|
||||||
if (root == null)
|
if (root == null)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.stardust.view.accessibility;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.support.annotation.Keep;
|
import android.support.annotation.Keep;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
|
|
||||||
@@ -49,9 +50,10 @@ public class NodeInfo {
|
|||||||
public boolean checkable;
|
public boolean checkable;
|
||||||
public boolean focused;
|
public boolean focused;
|
||||||
public boolean visibleToUser;
|
public boolean visibleToUser;
|
||||||
|
public NodeInfo parent;
|
||||||
|
|
||||||
|
|
||||||
public NodeInfo(UiObject node) {
|
public NodeInfo(UiObject node, NodeInfo parent) {
|
||||||
id = simplifyId(node.getViewIdResourceName());
|
id = simplifyId(node.getViewIdResourceName());
|
||||||
desc = node.desc();
|
desc = node.desc();
|
||||||
className = node.className();
|
className = node.className();
|
||||||
@@ -86,6 +88,8 @@ public class NodeInfo {
|
|||||||
node.getBoundsInParent(mBoundsInParent);
|
node.getBoundsInParent(mBoundsInParent);
|
||||||
bounds = boundsToString(mBoundsInScreen);
|
bounds = boundsToString(mBoundsInScreen);
|
||||||
|
|
||||||
|
this.parent = parent;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String simplifyId(String idResourceName) {
|
private String simplifyId(String idResourceName) {
|
||||||
@@ -109,13 +113,13 @@ public class NodeInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static NodeInfo capture(@NonNull UiObject parent) {
|
public static NodeInfo capture(@NonNull UiObject uiObject, @Nullable NodeInfo parent) {
|
||||||
NodeInfo nodeInfo = new NodeInfo(parent);
|
NodeInfo nodeInfo = new NodeInfo(uiObject, parent);
|
||||||
int childCount = parent.getChildCount();
|
int childCount = uiObject.getChildCount();
|
||||||
for (int i = 0; i < childCount; i++) {
|
for (int i = 0; i < childCount; i++) {
|
||||||
UiObject child = parent.child(i);
|
UiObject child = uiObject.child(i);
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
nodeInfo.children.add(capture(child));
|
nodeInfo.children.add(capture(child, nodeInfo));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodeInfo;
|
return nodeInfo;
|
||||||
@@ -123,11 +127,48 @@ public class NodeInfo {
|
|||||||
|
|
||||||
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
||||||
UiObject r = UiObject.createRoot(root);
|
UiObject r = UiObject.createRoot(root);
|
||||||
return capture(r);
|
return capture(r, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<NodeInfo> getChildren() {
|
public List<NodeInfo> getChildren() {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return className + "{" +
|
||||||
|
"childCount=" + children.size() +
|
||||||
|
", mBoundsInScreen=" + mBoundsInScreen +
|
||||||
|
", mBoundsInParent=" + mBoundsInParent +
|
||||||
|
", id='" + id + '\'' +
|
||||||
|
", desc='" + desc + '\'' +
|
||||||
|
", packageName='" + packageName + '\'' +
|
||||||
|
", text='" + text + '\'' +
|
||||||
|
", depth=" + depth +
|
||||||
|
", drawingOrder=" + drawingOrder +
|
||||||
|
", accessibilityFocused=" + accessibilityFocused +
|
||||||
|
", checked=" + checked +
|
||||||
|
", clickable=" + clickable +
|
||||||
|
", contextClickable=" + contextClickable +
|
||||||
|
", dismissable=" + dismissable +
|
||||||
|
", editable=" + editable +
|
||||||
|
", enabled=" + enabled +
|
||||||
|
", focusable=" + focusable +
|
||||||
|
", longClickable=" + longClickable +
|
||||||
|
", row=" + row +
|
||||||
|
", column=" + column +
|
||||||
|
", rowCount=" + rowCount +
|
||||||
|
", columnCount=" + columnCount +
|
||||||
|
", rowSpan=" + rowSpan +
|
||||||
|
", columnSpan=" + columnSpan +
|
||||||
|
", selected=" + selected +
|
||||||
|
", scrollable=" + scrollable +
|
||||||
|
", bounds='" + bounds + '\'' +
|
||||||
|
", checkable=" + checkable +
|
||||||
|
", focused=" + focused +
|
||||||
|
", visibleToUser=" + visibleToUser +
|
||||||
|
", parent=" + parent.className +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user