/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v4.view.accessibility; import android.graphics.Rect; import android.os.Build; import android.view.View; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Helper for accessing AccessibilityNodeInfo from newer platform versions. */ public class AccessibilityNodeInfoCompat { static interface AccessibilityNodeInfoImpl { public Object obtain(); public Object obtain(View source); public Object obtain(Object info); public void setSource(Object info, View source); public int getWindowId(Object info); public int getChildCount(Object info); public Object getChild(Object info, int index); public void addChild(Object info, View child); public int getActions(Object info); public void addAction(Object info, int action); public boolean performAction(Object info, int action); public List findAccessibilityNodeInfosByText(Object info, String text); public Object getParent(Object info); public void setParent(Object info, View parent); public void getBoundsInParent(Object info, Rect outBounds); public void setBoundsInParent(Object info, Rect bounds); public void getBoundsInScreen(Object info, Rect outBounds); public void setBoundsInScreen(Object info, Rect bounds); public boolean isCheckable(Object info); public void setCheckable(Object info, boolean checkable); public boolean isChecked(Object info); public void setChecked(Object info, boolean checked); public boolean isFocusable(Object info); public void setFocusable(Object info, boolean focusable); public boolean isFocused(Object info); public void setFocused(Object info, boolean focused); public boolean isSelected(Object info); public void setSelected(Object info, boolean selected); public boolean isClickable(Object info); public void setClickable(Object info, boolean clickable); public boolean isLongClickable(Object info); public void setLongClickable(Object info, boolean longClickable); public boolean isEnabled(Object info); public void setEnabled(Object info, boolean enabled); public boolean isPassword(Object info); public void setPassword(Object info, boolean password); public boolean isScrollable(Object info); public void setScrollable(Object info, boolean scrollable); public CharSequence getPackageName(Object info); public void setPackageName(Object info, CharSequence packageName); public CharSequence getClassName(Object info); public void setClassName(Object info, CharSequence className); public CharSequence getText(Object info); public void setText(Object info, CharSequence text); public CharSequence getContentDescription(Object info); public void setContentDescription(Object info, CharSequence contentDescription); public void recycle(Object info); } static class AccessibilityNodeInfoStubImpl implements AccessibilityNodeInfoImpl { public Object obtain() { return null; } public Object obtain(View source) { return null; } public Object obtain(Object info) { return null; } public void addAction(Object info, int action) { } public void addChild(Object info, View child) { } public List findAccessibilityNodeInfosByText(Object info, String text) { return Collections.emptyList(); } public int getActions(Object info) { return 0; } public void getBoundsInParent(Object info, Rect outBounds) { } public void getBoundsInScreen(Object info, Rect outBounds) { } public Object getChild(Object info, int index) { return null; } public int getChildCount(Object info) { return 0; } public CharSequence getClassName(Object info) { return null; } public CharSequence getContentDescription(Object info) { return null; } public CharSequence getPackageName(Object info) { return null; } public AccessibilityNodeInfoCompat getParent(Object info) { return null; } public CharSequence getText(Object info) { return null; } public int getWindowId(Object info) { return 0; } public boolean isCheckable(Object info) { return false; } public boolean isChecked(Object info) { return false; } public boolean isClickable(Object info) { return false; } public boolean isEnabled(Object info) { return false; } public boolean isFocusable(Object info) { return false; } public boolean isFocused(Object info) { return false; } public boolean isLongClickable(Object info) { return false; } public boolean isPassword(Object info) { return false; } public boolean isScrollable(Object info) { return false; } public boolean isSelected(Object info) { return false; } public boolean performAction(Object info, int action) { return false; } public void setBoundsInParent(Object info, Rect bounds) { } public void setBoundsInScreen(Object info, Rect bounds) { } public void setCheckable(Object info, boolean checkable) { } public void setChecked(Object info, boolean checked) { } public void setClassName(Object info, CharSequence className) { } public void setClickable(Object info, boolean clickable) { } public void setContentDescription(Object info, CharSequence contentDescription) { } public void setEnabled(Object info, boolean enabled) { } public void setFocusable(Object info, boolean focusable) { } public void setFocused(Object info, boolean focused) { } public void setLongClickable(Object info, boolean longClickable) { } public void setPackageName(Object info, CharSequence packageName) { } public void setParent(Object info, View parent) { } public void setPassword(Object info, boolean password) { } public void setScrollable(Object info, boolean scrollable) { } public void setSelected(Object info, boolean selected) { } public void setSource(Object info, View source) { } public void setText(Object info, CharSequence text) { } public void recycle(Object info) { } } static class AccessibilityNodeInfoIcsImpl extends AccessibilityNodeInfoStubImpl { @Override public Object obtain() { return AccessibilityNodeInfoCompatIcs.obtain(); } @Override public Object obtain(View source) { return AccessibilityNodeInfoCompatIcs.obtain(source); } @Override public Object obtain(Object info) { return AccessibilityNodeInfoCompatIcs.obtain(info); } @Override public void addAction(Object info, int action) { AccessibilityNodeInfoCompatIcs.addAction(info, action); } @Override public void addChild(Object info, View child) { AccessibilityNodeInfoCompatIcs.addChild(info, child); } @Override public List findAccessibilityNodeInfosByText(Object info, String text) { return AccessibilityNodeInfoCompatIcs.findAccessibilityNodeInfosByText(info, text); } @Override public int getActions(Object info) { return AccessibilityNodeInfoCompatIcs.getActions(info); } @Override public void getBoundsInParent(Object info, Rect outBounds) { AccessibilityNodeInfoCompatIcs.getBoundsInParent(info, outBounds); } @Override public void getBoundsInScreen(Object info, Rect outBounds) { AccessibilityNodeInfoCompatIcs.getBoundsInScreen(info, outBounds); } @Override public AccessibilityNodeInfoCompat getChild(Object info, int index) { return new AccessibilityNodeInfoCompat(IMPL.getChild(info, index)); } @Override public int getChildCount(Object info) { return AccessibilityNodeInfoCompatIcs.getChildCount(info); } @Override public CharSequence getClassName(Object info) { return AccessibilityNodeInfoCompatIcs.getClassName(info); } @Override public CharSequence getContentDescription(Object info) { return AccessibilityNodeInfoCompatIcs.getContentDescription(info); } @Override public CharSequence getPackageName(Object info) { return AccessibilityNodeInfoCompatIcs.getPackageName(info); } @Override public AccessibilityNodeInfoCompat getParent(Object info) { return new AccessibilityNodeInfoCompat(IMPL.getParent(info)); } @Override public CharSequence getText(Object info) { return AccessibilityNodeInfoCompatIcs.getText(info); } @Override public int getWindowId(Object info) { return AccessibilityNodeInfoCompatIcs.getWindowId(info); } @Override public boolean isCheckable(Object info) { return AccessibilityNodeInfoCompatIcs.isCheckable(info); } @Override public boolean isChecked(Object info) { return AccessibilityNodeInfoCompatIcs.isChecked(info); } @Override public boolean isClickable(Object info) { return AccessibilityNodeInfoCompatIcs.isClickable(info); } @Override public boolean isEnabled(Object info) { return AccessibilityNodeInfoCompatIcs.isEnabled(info); } @Override public boolean isFocusable(Object info) { return AccessibilityNodeInfoCompatIcs.isFocusable(info); } @Override public boolean isFocused(Object info) { return AccessibilityNodeInfoCompatIcs.isFocused(info); } @Override public boolean isLongClickable(Object info) { return AccessibilityNodeInfoCompatIcs.isLongClickable(info); } @Override public boolean isPassword(Object info) { return AccessibilityNodeInfoCompatIcs.isPassword(info); } @Override public boolean isScrollable(Object info) { return AccessibilityNodeInfoCompatIcs.isScrollable(info); } @Override public boolean isSelected(Object info) { return AccessibilityNodeInfoCompatIcs.isSelected(info); } @Override public boolean performAction(Object info, int action) { return AccessibilityNodeInfoCompatIcs.performAction(info, action); } @Override public void setBoundsInParent(Object info, Rect bounds) { AccessibilityNodeInfoCompatIcs.setBoundsInParent(info, bounds); } @Override public void setBoundsInScreen(Object info, Rect bounds) { AccessibilityNodeInfoCompatIcs.setBoundsInScreen(info, bounds); } @Override public void setCheckable(Object info, boolean checkable) { AccessibilityNodeInfoCompatIcs.setCheckable(info, checkable); } @Override public void setChecked(Object info, boolean checked) { AccessibilityNodeInfoCompatIcs.setChecked(info, checked); } @Override public void setClassName(Object info, CharSequence className) { AccessibilityNodeInfoCompatIcs.setClassName(info, className); } @Override public void setClickable(Object info, boolean clickable) { AccessibilityNodeInfoCompatIcs.setClickable(info, clickable); } @Override public void setContentDescription(Object info, CharSequence contentDescription) { AccessibilityNodeInfoCompatIcs.setContentDescription(info, contentDescription); } @Override public void setEnabled(Object info, boolean enabled) { AccessibilityNodeInfoCompatIcs.setEnabled(info, enabled); } @Override public void setFocusable(Object info, boolean focusable) { AccessibilityNodeInfoCompatIcs.setFocusable(info, focusable); } @Override public void setFocused(Object info, boolean focused) { AccessibilityNodeInfoCompatIcs.setFocused(info, focused); } @Override public void setLongClickable(Object info, boolean longClickable) { AccessibilityNodeInfoCompatIcs.setLongClickable(info, longClickable); } @Override public void setPackageName(Object info, CharSequence packageName) { AccessibilityNodeInfoCompatIcs.setPackageName(info, packageName); } @Override public void setParent(Object info, View parent) { AccessibilityNodeInfoCompatIcs.setParent(info, parent); } @Override public void setPassword(Object info, boolean password) { AccessibilityNodeInfoCompatIcs.setPassword(info, password); } @Override public void setScrollable(Object info, boolean scrollable) { AccessibilityNodeInfoCompatIcs.setScrollable(info, scrollable); } @Override public void setSelected(Object info, boolean selected) { AccessibilityNodeInfoCompatIcs.setSelected(info, selected); } @Override public void setSource(Object info, View source) { AccessibilityNodeInfoCompatIcs.setSource(info, source); } @Override public void setText(Object info, CharSequence text) { AccessibilityNodeInfoCompatIcs.setText(info, text); } @Override public void recycle(Object info) { AccessibilityNodeInfoCompatIcs.recycle(info); } } static { if (Build.VERSION.SDK_INT >= 14) { // ICS IMPL = new AccessibilityNodeInfoIcsImpl(); } else { IMPL = new AccessibilityNodeInfoStubImpl(); } } private static final AccessibilityNodeInfoImpl IMPL; private final Object mInfo; // Actions. /** * Action that focuses the node. */ public static final int ACTION_FOCUS = 0x00000001; /** * Action that unfocuses the node. */ public static final int ACTION_CLEAR_FOCUS = 0x00000002; /** * Action that selects the node. */ public static final int ACTION_SELECT = 0x00000004; /** * Action that unselects the node. */ public static final int ACTION_CLEAR_SELECTION = 0x00000008; /* * Hide constructor from clients. */ public AccessibilityNodeInfoCompat(Object info) { mInfo = info; } /** * @return The wrapped actual implementation. * * @hide */ public Object getImpl() { return mInfo; } /** * Returns a cached instance if such is available otherwise a new one and * sets the source. * * @return An instance. * @see #setSource(View) */ public static AccessibilityNodeInfoCompat obtain(View source) { return new AccessibilityNodeInfoCompat(IMPL.obtain(source)); } /** * Returns a cached instance if such is available otherwise a new one. * * @return An instance. */ public static AccessibilityNodeInfoCompat obtain() { return new AccessibilityNodeInfoCompat(IMPL.obtain()); } /** * Returns a cached instance if such is available or a new one is create. * The returned instance is initialized from the given info. * * @param info The other info. * @return An instance. */ public static AccessibilityNodeInfoCompat obtain(AccessibilityNodeInfoCompat info) { return new AccessibilityNodeInfoCompat(IMPL.obtain(info.mInfo)); } /** * Sets the source. * * @param source The info source. */ public void setSource(View source) { IMPL.setSource(mInfo, source); } /** * Gets the id of the window from which the info comes from. * * @return The window id. */ public int getWindowId() { return IMPL.getWindowId(mInfo); } /** * Gets the number of children. * * @return The child count. */ public int getChildCount() { return IMPL.getChildCount(mInfo); } /** * Get the child at given index. *

* Note: It is a client responsibility to recycle the * received info by calling {@link AccessibilityNodeInfoCompat#recycle()} to * avoid creating of multiple instances. *

* * @param index The child index. * @return The child node. * @throws IllegalStateException If called outside of an * AccessibilityService. */ public AccessibilityNodeInfoCompat getChild(int index) { return new AccessibilityNodeInfoCompat(IMPL.getChild(mInfo, index)); } /** * Adds a child. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param child The child. * @throws IllegalStateException If called from an AccessibilityService. */ public void addChild(View child) { IMPL.addChild(mInfo, child); } /** * Gets the actions that can be performed on the node. * * @return The bit mask of with actions. * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_FOCUS * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_FOCUS * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_SELECT * @see android.view.accessibility.AccessibilityNodeInfo#ACTION_CLEAR_SELECTION */ public int getActions() { return IMPL.getActions(mInfo); } /** * Adds an action that can be performed on the node. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param action The action. * @throws IllegalStateException If called from an AccessibilityService. */ public void addAction(int action) { IMPL.addAction(mInfo, action); } /** * Performs an action on the node. *

* Note: An action can be performed only if the request is * made from an {@link android.accessibilityservice.AccessibilityService}. *

* * @param action The action to perform. * @return True if the action was performed. * @throws IllegalStateException If called outside of an * AccessibilityService. */ public boolean performAction(int action) { return IMPL.performAction(mInfo, action); } /** * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by text. The match * is case insensitive containment. The search is relative to this info i.e. this * info is the root of the traversed tree. *

* Note: It is a client responsibility to recycle the * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()} * to avoid creating of multiple instances. *

* * @param text The searched text. * @return A list of node info. */ public List findAccessibilityNodeInfosByText(String text) { List result = new ArrayList(); List infos = IMPL.findAccessibilityNodeInfosByText(mInfo, text); final int infoCount = infos.size(); for (int i = 0; i < infoCount; i++) { Object info = infos.get(i); result.add(new AccessibilityNodeInfoCompat(info)); } return result; } /** * Gets the parent. *

* Note: It is a client responsibility to recycle the * received info by calling {@link android.view.accessibility.AccessibilityNodeInfo#recycle()} * to avoid creating of multiple instances. *

* * @return The parent. */ public AccessibilityNodeInfoCompat getParent() { return new AccessibilityNodeInfoCompat(IMPL.getParent(mInfo)); } /** * Sets the parent. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param parent The parent. * @throws IllegalStateException If called from an AccessibilityService. */ public void setParent(View parent) { IMPL.setParent(mInfo, parent); } /** * Gets the node bounds in parent coordinates. * * @param outBounds The output node bounds. */ public void getBoundsInParent(Rect outBounds) { IMPL.getBoundsInParent(mInfo, outBounds); } /** * Sets the node bounds in parent coordinates. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param bounds The node bounds. *@throws IllegalStateException If called from an AccessibilityService. */ public void setBoundsInParent(Rect bounds) { IMPL.setBoundsInParent(mInfo, bounds); } /** * Gets the node bounds in screen coordinates. * * @param outBounds The output node bounds. */ public void getBoundsInScreen(Rect outBounds) { IMPL.getBoundsInScreen(mInfo, outBounds); } /** * Sets the node bounds in screen coordinates. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param bounds The node bounds. * @throws IllegalStateException If called from an AccessibilityService. */ public void setBoundsInScreen(Rect bounds) { IMPL.setBoundsInParent(mInfo, bounds); } /** * Gets whether this node is checkable. * * @return True if the node is checkable. */ public boolean isCheckable() { return IMPL.isCheckable(mInfo); } /** * Sets whether this node is checkable. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param checkable True if the node is checkable. * @throws IllegalStateException If called from an AccessibilityService. */ public void setCheckable(boolean checkable) { IMPL.setCheckable(mInfo, checkable); } /** * Gets whether this node is checked. * * @return True if the node is checked. */ public boolean isChecked() { return IMPL.isChecked(mInfo); } /** * Sets whether this node is checked. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param checked True if the node is checked. * @throws IllegalStateException If called from an AccessibilityService. */ public void setChecked(boolean checked) { IMPL.setChecked(mInfo, checked); } /** * Gets whether this node is focusable. * * @return True if the node is focusable. */ public boolean isFocusable() { return IMPL.isFocusable(mInfo); } /** * Sets whether this node is focusable. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param focusable True if the node is focusable. * @throws IllegalStateException If called from an AccessibilityService. */ public void setFocusable(boolean focusable) { IMPL.setFocusable(mInfo, focusable); } /** * Gets whether this node is focused. * * @return True if the node is focused. */ public boolean isFocused() { return IMPL.isFocused(mInfo); } /** * Sets whether this node is focused. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param focused True if the node is focused. * @throws IllegalStateException If called from an AccessibilityService. */ public void setFocused(boolean focused) { IMPL.setFocused(mInfo, focused); } /** * Gets whether this node is selected. * * @return True if the node is selected. */ public boolean isSelected() { return IMPL.isSelected(mInfo); } /** * Sets whether this node is selected. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param selected True if the node is selected. * @throws IllegalStateException If called from an AccessibilityService. */ public void setSelected(boolean selected) { IMPL.setSelected(mInfo, selected); } /** * Gets whether this node is clickable. * * @return True if the node is clickable. */ public boolean isClickable() { return IMPL.isClickable(mInfo); } /** * Sets whether this node is clickable. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param clickable True if the node is clickable. * @throws IllegalStateException If called from an AccessibilityService. */ public void setClickable(boolean clickable) { IMPL.setClickable(mInfo, clickable); } /** * Gets whether this node is long clickable. * * @return True if the node is long clickable. */ public boolean isLongClickable() { return IMPL.isLongClickable(mInfo); } /** * Sets whether this node is long clickable. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param longClickable True if the node is long clickable. * @throws IllegalStateException If called from an AccessibilityService. */ public void setLongClickable(boolean longClickable) { IMPL.setLongClickable(mInfo, longClickable); } /** * Gets whether this node is enabled. * * @return True if the node is enabled. */ public boolean isEnabled() { return IMPL.isEnabled(mInfo); } /** * Sets whether this node is enabled. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param enabled True if the node is enabled. * @throws IllegalStateException If called from an AccessibilityService. */ public void setEnabled(boolean enabled) { IMPL.setEnabled(mInfo, enabled); } /** * Gets whether this node is a password. * * @return True if the node is a password. */ public boolean isPassword() { return IMPL.isPassword(mInfo); } /** * Sets whether this node is a password. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param password True if the node is a password. * @throws IllegalStateException If called from an AccessibilityService. */ public void setPassword(boolean password) { IMPL.setPassword(mInfo, password); } /** * Gets if the node is scrollable. * * @return True if the node is scrollable, false otherwise. */ public boolean isScrollable() { return IMPL.isScrollable(mInfo); } /** * Sets if the node is scrollable. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param scrollable True if the node is scrollable, false otherwise. * @throws IllegalStateException If called from an AccessibilityService. */ public void setScrollable(boolean scrollable) { IMPL.setScrollable(mInfo, scrollable); } /** * Gets the package this node comes from. * * @return The package name. */ public CharSequence getPackageName() { return IMPL.getPackageName(mInfo); } /** * Sets the package this node comes from. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param packageName The package name. * @throws IllegalStateException If called from an AccessibilityService. */ public void setPackageName(CharSequence packageName) { IMPL.setPackageName(mInfo, packageName); } /** * Gets the class this node comes from. * * @return The class name. */ public CharSequence getClassName() { return IMPL.getClassName(mInfo); } /** * Sets the class this node comes from. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param className The class name. * @throws IllegalStateException If called from an AccessibilityService. */ public void setClassName(CharSequence className) { IMPL.setClassName(mInfo, className); } /** * Gets the text of this node. * * @return The text. */ public CharSequence getText() { return IMPL.getText(mInfo); } /** * Sets the text of this node. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param text The text. * @throws IllegalStateException If called from an AccessibilityService. */ public void setText(CharSequence text) { IMPL.setText(mInfo, text); } /** * Gets the content description of this node. * * @return The content description. */ public CharSequence getContentDescription() { return IMPL.getContentDescription(mInfo); } /** * Sets the content description of this node. *

* Note: Cannot be called from an * {@link android.accessibilityservice.AccessibilityService}. This class is * made immutable before being delivered to an AccessibilityService. *

* * @param contentDescription The content description. * @throws IllegalStateException If called from an AccessibilityService. */ public void setContentDescription(CharSequence contentDescription) { IMPL.setContentDescription(mInfo, contentDescription); } /** * Return an instance back to be reused. *

* Note: You must not touch the object after calling this function. * * @throws IllegalStateException If the info is already recycled. */ public void recycle() { IMPL.recycle(mInfo); } @Override public int hashCode() { return (mInfo == null) ? 0 : mInfo.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AccessibilityNodeInfoCompat other = (AccessibilityNodeInfoCompat) obj; if (mInfo == null) { if (other.mInfo != null) { return false; } } else if (!mInfo.equals(other.mInfo)) { return false; } return true; } }