下面列出了android.view.accessibility.AccessibilityNodeInfo#isEnabled ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* 查找符合条件的节点
* @param service {@link AccessibilityService}
* @param focus 焦点类型
* @param className 节点所属的类 ( 类名 )
* @return 拥有特定焦点类型的节点
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static AccessibilityNodeInfo findFocus(final AccessibilityService service, final int focus, final String className) {
if (service == null || className == null) return null;
// 获取根节点
AccessibilityNodeInfo nodeInfo = service.getRootInActiveWindow();
// 取得当前激活窗体的根节点
if (nodeInfo == null) return null;
// 通过指定的焦点类型找到当前的节点
AccessibilityNodeInfo node = nodeInfo.findFocus(focus);
// 防止为 null
if (node != null) {
// 判断是否符合的类型
if (node.getClassName().equals(className) && node.isEnabled()) {
return node;
}
}
return null;
}
/**
* 查找符合条件的节点
* @param service {@link AccessibilityService}
* @param text 文本内容 ( 搜索包含该文本内容的节点 )
* @param className 节点所属的类 ( 类名 )
* @return 包含该文本内容, 且属于指定类的节点集合
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(final AccessibilityService service, final String text, final String className) {
if (service == null || text == null || className == null) return null;
List<AccessibilityNodeInfo> lists = new ArrayList<>();
// 获取根节点
AccessibilityNodeInfo nodeInfo = service.getRootInActiveWindow();
// 取得当前激活窗体的根节点
if (nodeInfo == null) return lists;
// 通过文字找到当前的节点
List<AccessibilityNodeInfo> nodes = nodeInfo.findAccessibilityNodeInfosByText(text);
for (int i = 0; i < nodes.size(); i++) {
AccessibilityNodeInfo node = nodes.get(i);
// 判断是否符合的类型
if (node.getClassName().equals(className) && node.isEnabled()) {
// 保存符合条件
lists.add(node);
}
}
return lists;
}
/**
* 查找符合条件的节点
* @param service {@link AccessibilityService}
* @param id viewId
* @param className 节点所属的类 ( 类名 )
* @return 等于 viewId, 且属于指定类的节点集合
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public static List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(final AccessibilityService service, final String id, final String className) {
if (service == null || id == null || className == null) return null;
List<AccessibilityNodeInfo> lists = new ArrayList<>();
// 获取根节点
AccessibilityNodeInfo nodeInfo = service.getRootInActiveWindow();
// 取得当前激活窗体的根节点
if (nodeInfo == null) return lists;
// 通过 id 找到当前的节点
List<AccessibilityNodeInfo> nodes = nodeInfo.findAccessibilityNodeInfosByViewId(id);
for (int i = 0; i < nodes.size(); i++) {
AccessibilityNodeInfo node = nodes.get(i);
// 判断是否符合的类型
if (node.getClassName().equals(className) && node.isEnabled()) {
// 保存符合条件
lists.add(node);
}
}
return lists;
}
public void refresh(AccessibilityNodeInfo node) {
if (sealed) {
throw new IllegalArgumentException("sealed! " + super.toString());
}
mFocused = node.isFocused();
node.getBoundsInScreen(mBoundsInScreen);
node.getBoundsInParent(mBoundsInParent);
mBoundsInScreen.offset(0, -OverlayDecryptView.SCREEN_OFFSET_Y);
mText = AccessibilityNodeInfoUtils.getNodeText(node);
mTextString = mText == null ? null : mText.toString();
mIsEncoded = mText == null ? false : CryptoHandlerFacade.Companion.isEncoded(mCtx, mTextString);
if (mIsEncoded) {
mIsTextView = true;
}
mIsEditableTextNode = (node.isEditable()
&& node.isEnabled()
&& mIsEditText
&& !node.isPassword());
}
public boolean isEditableEditTextFocussed() {
boolean res = false;
AccessibilityNodeInfo anode = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
anode = findFocus(AccessibilityNodeInfo.FOCUS_INPUT);
} else {
anode = findFocus_PreLollipop();
}
if (anode != null) {
if (anode.isEditable() && anode.isEnabled()) {
if (mTree.isAEditText(anode)) {
res = true;
}
}
anode.recycle();
}
return res;
}
private boolean matchNode(AccessibilityNodeInfo node) {
String clsName = node.getClassName().toString();
Class EDITTEXT, B, WEBVIEW;
boolean matchedEditText = false;
boolean matchedWebView = false;
try {
B = Class.forName(clsName, false, this.getClass().getClassLoader());
EDITTEXT = Class.forName(EditText.class.getCanonicalName(), false, this.getClass().getClassLoader());
matchedEditText = EDITTEXT.isAssignableFrom(B);
WEBVIEW = Class.forName(WebView.class.getCanonicalName(), false, this.getClass().getClassLoader());
matchedWebView = WEBVIEW.isAssignableFrom(B);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return node.isClickable() && node.isEnabled() && node.isVisibleToUser() && !node.isCheckable() && !matchedEditText && !matchedWebView;
}
/**
* Checks if the UI element's <code>enabled</code> property is currently true.
*
* @return true if it is else false
* @throws UiObjectNotFoundException
* @since API Level 16
*/
public boolean isEnabled() throws UiObjectNotFoundException {
Tracer.trace();
AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
if(node == null) {
throw new UiObjectNotFoundException(mUiSelector.toString());
}
return node.isEnabled();
}
/**
* We're looking for UI controls that are enabled, clickable but have no
* text nor content-description. Such controls configuration indicate an
* interactive control is present in the UI and is most likely not
* accessibility friendly. We refer to such controls here as NAF controls
* (Not Accessibility Friendly)
*
* @param node
* @return false if a node fails the check, true if all is OK
*/
private static boolean nafCheck(AccessibilityNodeInfo node) {
boolean isNaf = node.isClickable() && node.isEnabled()
&& safeCharSeqToString(node.getContentDescription()).isEmpty()
&& safeCharSeqToString(node.getText()).isEmpty();
if (!isNaf)
return true;
// check children since sometimes the containing element is clickable
// and NAF but a child's text or description is available. Will assume
// such layout as fine.
return childNafCheck(node);
}
/**
* We're looking for UI controls that are enabled, clickable but have no text nor
* content-description. Such controls configuration indicate an interactive control is present in
* the UI and is most likely not accessibility friendly. We refer to such controls here as NAF
* controls (Not Accessibility Friendly)
*
* @return false if a node fails the check, true if all is OK
*/
private static boolean nafCheck(AccessibilityNodeInfo node) {
boolean isNaf =
node.isClickable()
&& node.isEnabled()
&& safeCharSeqToString(node.getContentDescription()).isEmpty()
&& safeCharSeqToString(node.getText()).isEmpty();
if (!isNaf) {
return true;
}
// check children since sometimes the containing element is clickable
// and NAF but a child's text or description is available. Will assume
// such layout as fine.
return childNafCheck(node);
}
private void nextClick(List<AccessibilityNodeInfo> infos) {
if (infos != null)
for (AccessibilityNodeInfo info : infos) {
if (info.isEnabled() && info.isClickable())
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
/**
* Checks if the UI element's <code>enabled</code> property is currently true.
*
* @return true if it is else false
* @throws UiObjectNotFoundException
* @since API Level 16
*/
public boolean isEnabled() throws UiObjectNotFoundException {
Tracer.trace();
AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
if(node == null) {
throw new UiObjectNotFoundException(mUiSelector.toString());
}
return node.isEnabled();
}
public static void dumpNode(AccessibilityNodeInfo info, Node root,
int index, int width, int height) {
root.sourceId = info.getSourceNodeId();
root.index = index;
root.text = safeCharSeqToString(info.getText());
root.res = safeCharSeqToString(info.getViewIdResourceName());
root.clazz = safeCharSeqToString(info.getClassName());
root.pkg = safeCharSeqToString(info.getPackageName());
root.desc = safeCharSeqToString(info.getContentDescription());
root.checkable = info.isCheckable();
root.checked = info.isChecked();
root.clickable = info.isClickable();
root.enabled = info.isEnabled();
root.focusable = info.isFocusable();
root.focused = info.isFocused();
root.scrollable = info.isScrollable();
root.longClickable = info.isLongClickable();
root.password = info.isPassword();
root.selected = info.isSelected();
android.graphics.Rect r = AccessibilityNodeInfoHelper
.getVisibleBoundsInScreen(info, width, height);
root.rect = new Rect(r.left, r.top, r.right, r.bottom);
root.children = new ArrayList<Node>();
int count = info.getChildCount();
for (int i = 0; i < count; i++) {
AccessibilityNodeInfo child = info.getChild(i);
if (child != null) {
if (child.isVisibleToUser()) {
Node childNode = new Node();
dumpNode(child, childNode, i, width, height);
root.children.add(childNode);
child.recycle();
}
}
}
}
/**
* We're looking for UI controls that are enabled, clickable but have no
* text nor content-description. Such controls configuration indicate an
* interactive control is present in the UI and is most likely not
* accessibility friendly. We refer to such controls here as NAF controls
* (Not Accessibility Friendly)
*
* @param node
* @return false if a node fails the check, true if all is OK
*/
private static boolean nafCheck(AccessibilityNodeInfo node) {
boolean isNaf = node.isClickable() && node.isEnabled()
&& safeCharSeqToString(node.getContentDescription()).isEmpty()
&& safeCharSeqToString(node.getText()).isEmpty();
if (!isNaf)
return true;
// check children since sometimes the containing element is clickable
// and NAF but a child's text or description is available. Will assume
// such layout as fine.
return childNafCheck(node);
}
/**
* 自动点击按钮
* @param event
* @param nodeText 按钮文本
*/
public static void handleEvent(AccessibilityEvent event, String nodeText) {
List<AccessibilityNodeInfo> unintall_nodes = event.getSource().findAccessibilityNodeInfosByText(nodeText);
if (unintall_nodes != null && !unintall_nodes.isEmpty()) {
AccessibilityNodeInfo node;
for (int i = 0; i < unintall_nodes.size(); i++) {
node = unintall_nodes.get(i);
if (node.getClassName().equals("android.widget.Button") && node.isEnabled()) {
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
/**
* 執行點擊
*
* @param infos
*/
private void doClick(List<AccessibilityNodeInfo> infos) {
if (infos != null)
for (AccessibilityNodeInfo info : infos) {
if (info.isEnabled() && info.isClickable()) {
Log.i(TAG, "> doClick: " + info.getText());
info.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
/**
* performClickAction
* @param aAccessibilityNodeInfo aAccessibilityNodeInfo
* @return
*/
private boolean performClickAction(AccessibilityNodeInfo aAccessibilityNodeInfo) {
int targetAction = AccessibilityNodeInfo.ACTION_CLICK;
if ((aAccessibilityNodeInfo != null) && aAccessibilityNodeInfo.isEnabled() && aAccessibilityNodeInfo.isClickable()
&& aAccessibilityNodeInfo.performAction(targetAction)) {
return true;
}
return false;
}
/**
* We're looking for UI controls that are enabled, clickable but have no text nor
* content-description. Such controls configuration indicate an interactive control is present
* in the UI and is most likely not accessibility friendly. We refer to such controls here as
* NAF controls (Not Accessibility Friendly)
*
* @return false if a node fails the check, true if all is OK
*/
private static boolean nafCheck(AccessibilityNodeInfo node) {
boolean isNaf = node.isClickable() && node.isEnabled() && safeCharSeqToString(node.getContentDescription()).isEmpty() && safeCharSeqToString(node.getText()).isEmpty();
if (!isNaf) return true;
// check children since sometimes the containing element is clickable
// and NAF but a child's text or description is available. Will assume
// such layout as fine.
return childNafCheck(node);
}
Builder(int id, @Nullable ViewHierarchyElementAndroid parent, AccessibilityNodeInfo fromInfo) {
// Bookkeeping
this.id = id;
this.parentId = (parent != null) ? parent.getId() : null;
// API 18+ properties
this.resourceName = AT_18 ? fromInfo.getViewIdResourceName() : null;
this.editable = AT_18 ? fromInfo.isEditable() : null;
// API 16+ properties
this.visibleToUser = AT_16 ? fromInfo.isVisibleToUser() : null;
// API 21+ properties
if (AT_21) {
ImmutableList.Builder<ViewHierarchyActionAndroid> actionBuilder =
new ImmutableList.Builder<>();
actionBuilder.addAll(
Lists.transform(
fromInfo.getActionList(),
action -> ViewHierarchyActionAndroid.newBuilder(action).build()));
this.actionList = actionBuilder.build();
}
// API 24+ properties
this.drawingOrder = AT_24 ? fromInfo.getDrawingOrder() : null;
// API 29+ properties
this.hasTouchDelegate = AT_29 ? (fromInfo.getTouchDelegateInfo() != null) : null;
// Base properties
this.className = fromInfo.getClassName();
this.packageName = fromInfo.getPackageName();
this.accessibilityClassName = fromInfo.getClassName();
this.contentDescription = SpannableStringAndroid.valueOf(fromInfo.getContentDescription());
this.text = SpannableStringAndroid.valueOf(fromInfo.getText());
this.importantForAccessibility = true;
this.clickable = fromInfo.isClickable();
this.longClickable = fromInfo.isLongClickable();
this.focusable = fromInfo.isFocusable();
this.scrollable = fromInfo.isScrollable();
this.canScrollForward =
((fromInfo.getActions() & AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) != 0);
this.canScrollBackward =
((fromInfo.getActions() & AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) != 0);
this.checkable = fromInfo.isCheckable();
this.checked = fromInfo.isChecked();
this.touchDelegateBounds = new ArrayList<>(); // Populated after construction
android.graphics.Rect tempRect = new android.graphics.Rect();
fromInfo.getBoundsInScreen(tempRect);
this.boundsInScreen = new Rect(tempRect.left, tempRect.top, tempRect.right, tempRect.bottom);
this.nonclippedHeight = null;
this.nonclippedWidth = null;
this.textSize = null;
this.textColor = null;
this.backgroundDrawableColor = null;
this.typefaceStyle = null;
this.enabled = fromInfo.isEnabled();
}
private AccessibilityNodeInfo getScrollableNode(AccessibilityNodeInfo treeRoot) {
List<AccessibilityNodeInfo> ret = new ArrayList<AccessibilityNodeInfo>();
Queue<AccessibilityNodeInfo> Q = new LinkedList<AccessibilityNodeInfo>();
Q.add(treeRoot);
while (!Q.isEmpty()) {
AccessibilityNodeInfo node = Q.remove();
if (node == null) {
// Util.log("Processing NULL");
continue;
}
// Util.log("Processing " + node.getClassName());
// check current node
if (node.isVisibleToUser() && node.isEnabled() && node.isScrollable()) {
ret.add(node);
}
// add its children to queue
int childCnt = node.getChildCount();
if (childCnt > 0) {
for (int i = 0; i < childCnt; i++) {
AccessibilityNodeInfo child = node.getChild(i);
Q.add(child); // no need to check NULL, checked above
}
}
}
if (ret.isEmpty()) {
Util.log("No scrollable node found");
return null;
} else {
if (ret.size() > 1) {
Util.log("NOTE: Found " + ret.size() + " scrollable nodes.");
}
Util.log("Selected " + ret.get(0).getClassName());
return ret.get(0);
}
}