下面列出了android.view.accessibility.AccessibilityNodeInfo#getClassName ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private boolean isAListOrScrollView(AccessibilityNodeInfo node) {
CharSequence classname = node.getClassName();
if (classname == null) {
//ouch. Sometimes happens when scanning a webview
return false;
}
Boolean res = mClassesThatAreListOrScrollViews.get(classname.toString());
if (res == null) {
res = AccessibilityNodeInfoUtils.nodeMatchesAnyClassByType(mCtx,
node, ListView.class, ScrollView.class);
if (res) {
mClassesThatAreListOrScrollViews.put(node.getClassName().toString(), res);
}
}
return res;
}
public boolean isAEditText(AccessibilityNodeInfo node) {
CharSequence classname = node.getClassName();
if (classname == null) {
//ouch. Sometimes happens when scanning a webview
return false;
}
Boolean res = mClassesThatAreEditTexts.get(classname.toString());
if (res == null) {
res = AccessibilityNodeInfoUtils.nodeMatchesClassByType(mCtx, node,
EditText.class);
if (res) {
mClassesThatAreEditTexts.put(node.getClassName().toString(), res);
}
}
return res;
}
public boolean isATextView(AccessibilityNodeInfo node) {
CharSequence classname = node.getClassName();
if (classname == null) {
//ouch. Sometimes happens when scanning a webview
return false;
}
Boolean res = mClassesThatAreTextViews.get(classname.toString());
if (res == null) {
res = AccessibilityNodeInfoUtils.nodeMatchesClassByType(mCtx, node,
TextView.class);
if (res) {
mClassesThatAreTextViews.put(node.getClassName().toString(), res);
}
}
return res;
}
public void init(AccessibilityNodeInfo node) {
if (sealed) {
throw new IllegalArgumentException("sealed! " + super.toString());
}
mKey = node.hashCode();
mClassName = node.getClassName();
mPackageName = node.getPackageName();
mIsTextView = isATextView(node);
mIsEditText = isAEditText(node);
mIsWebView = isAWebView(node);
mBoundsInScreen = new Rect();
mBoundsInParent = new Rect();
mIsVisibleToUser = node.isVisibleToUser();
refresh(node);
}
/**
* Determines if the generating class of an
* {@link AccessibilityNodeInfo} matches a given {@link Class} by
* type.
*
* @param node A sealed {@link AccessibilityNodeInfo} dispatched by
* the accessibility framework.
* @param referenceClass A {@link Class} to match by type or inherited type.
* @return {@code true} if the {@link AccessibilityNodeInfo} object
* matches the {@link Class} by type or inherited type,
* {@code false} otherwise.
*/
public static boolean nodeMatchesClassByType(
Context context, AccessibilityNodeInfo node, Class<?> referenceClass) {
if ((node == null) || (referenceClass == null)) {
return false;
}
// Attempt to take a shortcut.
final CharSequence nodeClassName = node.getClassName();
if (TextUtils.equals(nodeClassName, referenceClass.getName())) {
return true;
}
final ClassLoadingManager loader = ClassLoadingManager.getInstance();
final CharSequence appPackage = node.getPackageName();
return loader.checkInstanceOf(context, nodeClassName, appPackage, referenceClass);
}
/**
* Determines if the class of an {@link AccessibilityNodeInfo} matches
* a given {@link Class} by package and name.
*
* @param node A sealed {@link AccessibilityNodeInfo} dispatched by
* the accessibility framework.
* @param referenceClassName A class name to match.
* @return {@code true} if the {@link AccessibilityNodeInfo} matches
* the class name.
*/
public static boolean nodeMatchesClassByName(
Context context, AccessibilityNodeInfo node, CharSequence referenceClassName) {
if ((node == null) || (referenceClassName == null)) {
return false;
}
// Attempt to take a shortcut.
final CharSequence nodeClassName = node.getClassName();
if (TextUtils.equals(nodeClassName, referenceClassName)) {
return true;
}
final ClassLoadingManager loader = ClassLoadingManager.getInstance();
final CharSequence appPackage = node.getPackageName();
return loader.checkInstanceOf(context, nodeClassName, appPackage, referenceClassName);
}
private void computeFeatureVector(Hashtable<String, Integer> map, AccessibilityNodeInfo node, int level) {
if (node == null || node.getClassName() == null) {
Util.err("node or class name is NULL");
return;
}
String type = node.getClassName().toString();
String key = type + "@" + level;
int count = map.containsKey(key) ? map.get(key) : 0;
count++;
map.put(key, count);
int child_cnt = node.getChildCount();
if (child_cnt > 0) {
// Util.log("Branch: " + key + ", " + count);
for (int i = 0; i < child_cnt; i++) {
AccessibilityNodeInfo child = node.getChild(i);
computeFeatureVector(map, child, level + 1);
}
} else {
// Util.log("Leaf: " + key + ", " + count);
}
}
public boolean isAWebView(AccessibilityNodeInfo node) {
CharSequence classname = node.getClassName();
if (classname == null) {
//ouch. Sometimes happens when scanning a webview
return false;
}
//TODO: might be different in older releases without chrome?
return ("android.webkit.WebView".equals(classname.toString())); //TODO: toString really needed?
}
@TargetApi(21)
public static void performSetText(AccessibilityNodeInfo nodeInfo,String text) {
if(nodeInfo == null) {
return;
}
CharSequence className = nodeInfo.getClassName();
if ("android.widget.EditText".equals(className)) {//||"android.widget.TextView".equals(className)
Bundle arguments = new Bundle();
arguments.putCharSequence(AccessibilityNodeInfo
.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
}
}
public static SerializedAccessibilityNodeInfo serialize(AccessibilityNodeInfo node){
SerializedAccessibilityNodeInfo serializedNode = new SerializedAccessibilityNodeInfo();
Rect boundsInScreen = new Rect(), boundsInParent = new Rect();
if(node == null){
return null;
}
if(node.getClassName() != null)
serializedNode.className = node.getClassName().toString();
node.getBoundsInScreen(boundsInScreen);
node.getBoundsInParent(boundsInParent);
serializedNode.boundsInScreen = boundsInScreen.flattenToString();
serializedNode.boundsInParent = boundsInParent.flattenToString();
if(node.getContentDescription() != null)
serializedNode.contentDescription = node.getContentDescription().toString();
if(node.getText() != null){
serializedNode.text = node.getText().toString();
}
if(node.getViewIdResourceName() != null)
serializedNode.viewId = node.getViewIdResourceName();
int childCount = node.getChildCount();
for(int i = 0; i < childCount; i ++){
if(node.getChild(i) != null){
serializedNode.children.add(serialize(node.getChild(i)));
}
}
return serializedNode;
}
private static String print(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo == null)
return "";
CharSequence text = nodeInfo.getText();
CharSequence description = nodeInfo.getContentDescription();
CharSequence className = nodeInfo.getClassName();
CharSequence packageName = nodeInfo.getPackageName();
boolean focusable = nodeInfo.isFocusable();
boolean clickable = nodeInfo.isClickable();
Rect rect = new Rect();
nodeInfo.getBoundsInScreen(rect);
String viewId = nodeInfo.getViewIdResourceName();
return "| "
+ "text: " + text + " \t"
+ "description: " + description + " \t"
+ String.format("%-40s", "ID: " + viewId) + " \t"
+ String.format("%-40s", "class: " + className) + " \t"
+ String.format("%-30s", "location: " + rect) + " \t"
// + "focusable: " + focusable + " \t"
// + "clickable: " + clickable + " \t"
// + String.format("%-30s", "package: " + packageName) + " \t"
;
}
/**
* performClickActionWithFindNode.
* @param aAccessibilityNodeInfo aAccessibilityNodeInfo
* @param aClassName aClassName
* @param aNodeTxt aNodeTxt
* @param isGlobal isGlobal
* @return true
*/
private boolean performClickActionWithFindNode(AccessibilityNodeInfo aAccessibilityNodeInfo, String aClassName, String aNodeTxt, boolean isGlobal) {
if(aAccessibilityNodeInfo == null) {
return false;
} else {
List<AccessibilityNodeInfo> targetList = aAccessibilityNodeInfo.findAccessibilityNodeInfosByText(aNodeTxt);
if (targetList != null) {
for (AccessibilityNodeInfo targetNode : targetList) {
if (aClassName != null) {
String targetClassName = targetNode.getClassName() == null ? "" : targetNode.getClassName().toString();
if (!aClassName.equals(targetClassName)) {
continue;
}
}
String targetNodeText = targetNode.getText() == null ? "" : targetNode.getText().toString();
if (!aNodeTxt.equals(targetNodeText)) {
continue;
}
if (isGlobal && !isAutoRunning) {
performGlobalAction(AccessibilityNodeInfo.ACTION_FOCUS);
} else {
performClickAction(targetNode);
}
return true;
}
}
}
return false;
}
@Nullable
private static BySelector toSelector(@Nullable AccessibilityNodeInfo nodeInfo) {
if (nodeInfo == null) {
return null;
}
final CharSequence className = nodeInfo.getClassName();
return className == null ? null : By.clazz(className.toString());
}
private void sendWindowChangeEventsToWindowChangedListener(
WindowChangedListener windowChangedListener, List<AccessibilityEvent> windowChangeEventList) {
if (isRunning) {
while (!windowChangeEventList.isEmpty()) {
AccessibilityEvent event = windowChangeEventList.get(0);
CharSequence packageName = event.getPackageName();
if (service.getPackageName().equals(packageName)) {
AccessibilityNodeInfo info = event.getSource();
if (info != null) {
CharSequence className = info.getClassName();
// Check whether the window events in the event list are triggered by opening the
// Switch Access menu window. If so, clears the event list and calls
// WindowChangeListener#onSwitchAccessMenuShown to generate screen feedback for
// the Switch Access menu.
//
// We use two criteria to check if a window is a Switch Access menu window:
// 1. The package of the event is the same as the Switch Access Accessibility
// Service.
// 2. The source AccessibilityNodeInfoCompat of the event has the same class name
// as SwitchAccessMenuOverlay.
if (switchAccessMenus.containsKey(className)) {
windowChangedListener.onSwitchAccessMenuShown(switchAccessMenus.get(className));
windowChangeEventList.clear();
return;
}
}
}
windowChangedListener.onWindowChangedAndIsNowStable(
windowChangeEventList.get(0), Performance.EVENT_ID_UNTRACKED);
windowChangeEventList.remove(0);
}
}
}
private void computeFeatureVectorExactMatch(Hashtable<String, Integer> dict, Hashtable<String, Integer> map, AccessibilityNodeInfo node, int level) {
if (node == null || node.getClassName() == null) {
Util.err("node or class name is NULL");
return;
}
String type = node.getClassName().toString();
String key = type + "@" + level;
int count = dict.containsKey(key) ? dict.get(key) : 0;
count++;
dict.put(key, count);
String keyExactMatch = type + "@" + level + "@" + count + "@" + getTextDigest(node.getText());
map.put(keyExactMatch, 1);
int child_cnt = node.getChildCount();
if (child_cnt > 0) {
// Util.log("Branch: " + key + ", " + count);
for (int i = 0; i < child_cnt; i++) {
AccessibilityNodeInfo child = node.getChild(i);
computeFeatureVectorExactMatch(dict, map, child, level + 1);
}
} else {
// Util.log("Leaf: " + key + ", " + count);
}
}
protected void parser(AccessibilityNodeInfo group) {
if (group.getChildCount() == 0)
return;
int headIconPos = 0;
int messagePos = 0;
subName = "";
message = "";
isRecalledMsg = false;
for (int j = 0; j < group.getChildCount(); j++) {
AccessibilityNodeInfo child = group.getChild(j);
if (child == null) {
Log.d(TAG, "parser: child is null, continue");
continue;
}
String nodeId = child.getViewIdResourceName();
if (nodeId == null) {
Log.d(TAG, "parser: node ID is null, continue");
continue;
}
switch (nodeId) {
case IdHeadIcon:
//头像图标
headIconPos = j;
break;
case IdChatItem:
switch (child.getClassName() + "") {
case "android.widget.RelativeLayout":
if (child.getChildCount() != 0) {
if (child.getContentDescription() != null) {
redPegNode = child;
message = "红包";
//红包或者是分享
Log.d(TAG, "content_layout: 红包");
}
} else {
message = "[图片]";
Log.d(TAG, "content_layout: 图片");
}
break;
case "android.widget.LinearLayout": {
if (child.getChildCount() == 2) {
AccessibilityNodeInfo child1 = child.getChild(0);
AccessibilityNodeInfo child2 = child.getChild(1);
if (child1 != null && "android.widget.RelativeLayout".contentEquals(child1.getClassName())) {
if (child2 != null && "android.widget.TextView".contentEquals(child2.getClassName())) {
// message = "回复 " + child1.getText() + ": \n" + child2.getText();
message = child2.getText() + "";
}
}
}
Log.d(TAG, "content_layout: 回复消息");
}
break;
case "android.widget.TextView": {
message = child.getText() + "";
Log.v(TAG, "content_layout: 普通文本");
}
break;
}
messagePos = j;
break;
case IdNickName:
subName = child.getText() + "";
break;
case IdGrayBar:
message = child.getText() + "";
Log.w(TAG, "parser: message: " + message);
int indexOfRecall = message.indexOf(RECALL);
if (indexOfRecall >= 0) {
isRecalledMsg = true;
subName = message.substring(0, indexOfRecall);
message = RECALL;
if ("对方".equals(subName))
subName = title;
else if ("你".equals(subName))
subName = "我";
Log.v(TAG, "content_layout: 灰底文本");
}
Log.w(TAG, "parser: " + indexOfRecall + " " + RECALL + " " + message);
break;
}
}
if (messagePos < headIconPos)
// 消息在头像左边
subName = "我";
else if ("".equals(subName))
// 两人聊天时 没有subName
subName = title;
Log.v(TAG, "parser: " + title + " - " + subName + " : " + message);
}
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();
}