下面列出了android.view.accessibility.AccessibilityNodeInfo#isScrollable ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/** Returns the visible bounds of {@code node} in screen coordinates. */
private Rect getVisibleBounds(AccessibilityNodeInfo node) {
// Get the object bounds in screen coordinates
Rect ret = new Rect();
node.getBoundsInScreen(ret);
// Trim any portion of the bounds that are not on the screen
Rect screen = new Rect(0, 0, mDevice.getDisplayWidth(), mDevice.getDisplayHeight());
ret.intersect(screen);
// Find the visible bounds of our first scrollable ancestor
AccessibilityNodeInfo ancestor = null;
for (ancestor = node.getParent(); ancestor != null; ancestor = ancestor.getParent()) {
// If this ancestor is scrollable
if (ancestor.isScrollable()) {
// Trim any portion of the bounds that are hidden by the non-visible portion of our
// ancestor
Rect ancestorRect = getVisibleBounds(ancestor);
ret.intersect(ancestorRect);
break;
}
}
return ret;
}
private void initAccessibilityNodeInfo(AccessibilityNodeInfo info) {
this.className = StringUtil.nonNullString(info.getClassName());
this.packageName = StringUtil.nonNullString(info.getPackageName());
this.resourceId = info.getViewIdResourceName();
this.text = StringUtil.nonNullString(info.getText());
this.description = StringUtil.nonNullString(info.getContentDescription());
Rect rect = new Rect();
info.getBoundsInScreen(rect);
this.nodeBound = rect;
this.isScrollable = info.isScrollable();
this.visible = info.isVisibleToUser();
this.isClickable = info.isClickable();
this.isFocusable = info.isFocusable();
this.isEditable = info.isEditable();
}
/**
* Walks up the layout hierarchy to find a scrollable parent. A scrollable parent
* indicates that this node might be in a container where it is partially
* visible due to scrolling. In this case, its clickable center might not be visible and
* the click coordinates should be adjusted.
*
* @param node
* @return The accessibility node info.
*/
private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
AccessibilityNodeInfo parent = node;
while(parent != null) {
parent = parent.getParent();
if (parent != null && parent.isScrollable()) {
return parent;
}
}
return null;
}
/**
* Check if the view's <code>scrollable</code> property is currently true
*
* @return true if it is else false
* @throws UiObjectNotFoundException
* @since API Level 16
*/
public boolean isScrollable() throws UiObjectNotFoundException {
Tracer.trace();
AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
if(node == null) {
throw new UiObjectNotFoundException(mUiSelector.toString());
}
return node.isScrollable();
}
/**
* Walks up the layout hierarchy to find a scrollable parent. A scrollable parent
* indicates that this node might be in a container where it is partially
* visible due to scrolling. In this case, its clickable center might not be visible and
* the click coordinates should be adjusted.
*
* @param node
* @return The accessibility node info.
*/
private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
AccessibilityNodeInfo parent = node;
while(parent != null) {
parent = parent.getParent();
if (parent != null && parent.isScrollable()) {
return parent;
}
}
return null;
}
/**
* Check if the view's <code>scrollable</code> property is currently true
*
* @return true if it is else false
* @throws UiObjectNotFoundException
* @since API Level 16
*/
public boolean isScrollable() throws UiObjectNotFoundException {
Tracer.trace();
AccessibilityNodeInfo node = findAccessibilityNodeInfo(mConfig.getWaitForSelectorTimeout());
if(node == null) {
throw new UiObjectNotFoundException(mUiSelector.toString());
}
return node.isScrollable();
}
/** Returns the visible bounds of {@code node} in screen coordinates. */
private Rect getVisibleBounds(AccessibilityNodeInfo node) {
// Get the object bounds in screen coordinates
Rect ret = new Rect();
node.getBoundsInScreen(ret);
// Trim any portion of the bounds that are not on the screen
Rect screen = new Rect(0, 0, mDevice.getDisplayWidth(),
mDevice.getDisplayHeight());
ret.intersect(screen);
// Find the visible bounds of our first scrollable ancestor
AccessibilityNodeInfo ancestor = null;
for (ancestor = node.getParent(); ancestor != null; ancestor = ancestor
.getParent()) {
// If this ancestor is scrollable
if (ancestor.isScrollable()) {
// Trim any portion of the bounds that are hidden by the
// non-visible portion of our
// ancestor
Rect ancestorRect = getVisibleBounds(ancestor);
ret.intersect(ancestorRect);
break;
}
}
return ret;
}
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();
}
}
}
}
private boolean isValidScrollEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if (source == null) {
return true; // Cannot check source validity, so assume that it's scrollable.
}
boolean valid =
source.isScrollable() || event.getMaxScrollX() != -1 || event.getMaxScrollY() != -1;
source.recycle();
return valid;
}
/**
* Walk the hierarchy up to find a scrollable parent. A scrollable parent
* indicates that this node may be in a content where it is partially
* visible due to scrolling. its clickable center maybe invisible and
* adjustments should be made to the click coordinates.
*
* @param node
* @return The accessibility node info.
*/
private AccessibilityNodeInfo getScrollableParent(AccessibilityNodeInfo node) {
AccessibilityNodeInfo parent = node;
while (parent != null) {
parent = parent.getParent();
if (parent != null && parent.isScrollable()) {
return parent;
}
}
return null;
}
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);
}
}