Merge "Prohibit using recycled AccessibilityNodeInfos."
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 53efe18..ec6797c 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -651,7 +651,7 @@
private static AtomicInteger sNumInstancesInUse;
/**
- * Gets the accessibility view id which identifies a View in the view three.
+ * Gets the accessibility view id which identifies a View in the view tree.
*
* @param accessibilityNodeId The id of an {@link AccessibilityNodeInfo}.
* @return The accessibility view id part of the node id.
@@ -743,6 +743,7 @@
private RangeInfo mRangeInfo;
private CollectionInfo mCollectionInfo;
private CollectionItemInfo mCollectionItemInfo;
+ private boolean mRecycled;
/**
* Hide constructor from clients.
@@ -785,6 +786,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setSource(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
mWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED_ITEM_ID;
final int rootAccessibilityViewId =
@@ -804,6 +806,7 @@
* @see #FOCUS_ACCESSIBILITY
*/
public AccessibilityNodeInfo findFocus(int focus) {
+ enforceNotRecycled();
enforceSealed();
enforceValidFocusType(focus);
if (!canPerformRequestOverConnection(mSourceNodeId)) {
@@ -828,6 +831,7 @@
* @return The node info for the view that can take accessibility focus.
*/
public AccessibilityNodeInfo focusSearch(int direction) {
+ enforceNotRecycled();
enforceSealed();
enforceValidFocusDirection(direction);
if (!canPerformRequestOverConnection(mSourceNodeId)) {
@@ -843,6 +847,7 @@
* @return The window id.
*/
public int getWindowId() {
+ enforceNotRecycled();
return mWindowId;
}
@@ -860,6 +865,7 @@
* @hide
*/
public boolean refresh(Bundle arguments, boolean bypassCache) {
+ enforceNotRecycled();
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return false;
@@ -923,6 +929,7 @@
* @hide
*/
public long getChildId(int index) {
+ enforceNotRecycled();
if (mChildNodeIds == null) {
throw new IndexOutOfBoundsException();
}
@@ -935,6 +942,7 @@
* @return The child count.
*/
public int getChildCount() {
+ enforceNotRecycled();
return mChildNodeIds == null ? 0 : mChildNodeIds.size();
}
@@ -953,6 +961,7 @@
*
*/
public AccessibilityNodeInfo getChild(int index) {
+ enforceNotRecycled();
enforceSealed();
if (mChildNodeIds == null) {
return null;
@@ -1029,6 +1038,7 @@
}
private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
+ enforceNotRecycled();
enforceNotSealed();
if (mChildNodeIds == null) {
mChildNodeIds = new LongArray();
@@ -1054,6 +1064,7 @@
* @see #addChild(View, int)
*/
public boolean removeChild(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
final LongArray childIds = mChildNodeIds;
if (childIds == null) {
@@ -1074,6 +1085,7 @@
* Gets the actions that can be performed on the node.
*/
public List<AccessibilityAction> getActionList() {
+ enforceNotRecycled();
return CollectionUtils.emptyIfNull(mActions);
}
@@ -1101,6 +1113,7 @@
*/
@Deprecated
public int getActions() {
+ enforceNotRecycled();
int returnValue = 0;
if (mActions == null) {
@@ -1139,6 +1152,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void addAction(AccessibilityAction action) {
+ enforceNotRecycled();
enforceNotSealed();
addActionUnchecked(action);
@@ -1174,6 +1188,7 @@
*/
@Deprecated
public void addAction(int action) {
+ enforceNotRecycled();
enforceNotSealed();
if ((action & ACTION_TYPE_MASK) != 0) {
@@ -1200,6 +1215,7 @@
*/
@Deprecated
public void removeAction(int action) {
+ enforceNotRecycled();
enforceNotSealed();
removeAction(getActionSingleton(action));
@@ -1220,6 +1236,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public boolean removeAction(AccessibilityAction action) {
+ enforceNotRecycled();
enforceNotSealed();
if (mActions == null || action == null) {
@@ -1235,6 +1252,7 @@
* @hide
*/
public void removeAllActions() {
+ enforceNotRecycled();
if (mActions != null) {
mActions.clear();
}
@@ -1250,6 +1268,7 @@
* @see #setTraversalBefore(android.view.View, int)
*/
public AccessibilityNodeInfo getTraversalBefore() {
+ enforceNotRecycled();
enforceSealed();
return getNodeForAccessibilityId(mTraversalBefore);
}
@@ -1294,6 +1313,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setTraversalBefore(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
final int rootAccessibilityViewId = (root != null)
? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
@@ -1311,6 +1331,7 @@
* @see #setTraversalAfter(android.view.View, int)
*/
public AccessibilityNodeInfo getTraversalAfter() {
+ enforceNotRecycled();
enforceSealed();
return getNodeForAccessibilityId(mTraversalAfter);
}
@@ -1354,6 +1375,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setTraversalAfter(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
final int rootAccessibilityViewId = (root != null)
? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
@@ -1371,6 +1393,7 @@
* @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
*/
public List<String> getAvailableExtraData() {
+ enforceNotRecycled();
if (mExtraDataKeys != null) {
return Collections.unmodifiableList(mExtraDataKeys);
} else {
@@ -1395,6 +1418,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setAvailableExtraData(List<String> extraDataKeys) {
+ enforceNotRecycled();
enforceNotSealed();
mExtraDataKeys = new ArrayList<>(extraDataKeys);
}
@@ -1415,6 +1439,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setMaxTextLength(int max) {
+ enforceNotRecycled();
enforceNotSealed();
mMaxTextLength = max;
}
@@ -1426,6 +1451,7 @@
* @see #setMaxTextLength(int)
*/
public int getMaxTextLength() {
+ enforceNotRecycled();
return mMaxTextLength;
}
@@ -1442,6 +1468,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setMovementGranularities(int granularities) {
+ enforceNotRecycled();
enforceNotSealed();
mMovementGranularities = granularities;
}
@@ -1452,6 +1479,7 @@
* @return The bit mask with granularities.
*/
public int getMovementGranularities() {
+ enforceNotRecycled();
return mMovementGranularities;
}
@@ -1468,6 +1496,7 @@
* @throws IllegalStateException If called outside of an AccessibilityService.
*/
public boolean performAction(int action) {
+ enforceNotRecycled();
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return false;
@@ -1491,6 +1520,7 @@
* @throws IllegalStateException If called outside of an AccessibilityService.
*/
public boolean performAction(int action, Bundle arguments) {
+ enforceNotRecycled();
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return false;
@@ -1515,6 +1545,7 @@
* @return A list of node info.
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
+ enforceNotRecycled();
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return Collections.emptyList();
@@ -1546,6 +1577,7 @@
* @return A list of node info.
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
+ enforceNotRecycled();
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return Collections.emptyList();
@@ -1563,6 +1595,7 @@
* @see android.accessibilityservice.AccessibilityService#getWindows()
*/
public AccessibilityWindowInfo getWindow() {
+ enforceNotRecycled();
enforceSealed();
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return null;
@@ -1582,6 +1615,7 @@
* @return The parent.
*/
public AccessibilityNodeInfo getParent() {
+ enforceNotRecycled();
enforceSealed();
return getNodeForAccessibilityId(mParentNodeId);
}
@@ -1631,6 +1665,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setParent(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
final int rootAccessibilityViewId =
(root != null) ? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
@@ -1643,6 +1678,7 @@
* @param outBounds The output node bounds.
*/
public void getBoundsInParent(Rect outBounds) {
+ enforceNotRecycled();
outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
mBoundsInParent.right, mBoundsInParent.bottom);
}
@@ -1660,6 +1696,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setBoundsInParent(Rect bounds) {
+ enforceNotRecycled();
enforceNotSealed();
mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
@@ -1670,6 +1707,7 @@
* @param outBounds The output node bounds.
*/
public void getBoundsInScreen(Rect outBounds) {
+ enforceNotRecycled();
outBounds.set(mBoundsInScreen.left, mBoundsInScreen.top,
mBoundsInScreen.right, mBoundsInScreen.bottom);
}
@@ -1680,6 +1718,7 @@
* @hide Not safe to expose outside the framework.
*/
public Rect getBoundsInScreen() {
+ enforceNotRecycled();
return mBoundsInScreen;
}
@@ -1696,6 +1735,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setBoundsInScreen(Rect bounds) {
+ enforceNotRecycled();
enforceNotSealed();
mBoundsInScreen.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
@@ -2037,6 +2077,7 @@
* @return The drawing position of the view corresponding to this node relative to its siblings.
*/
public int getDrawingOrder() {
+ enforceNotRecycled();
return mDrawingOrderInParent;
}
@@ -2052,6 +2093,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setDrawingOrder(int drawingOrderInParent) {
+ enforceNotRecycled();
enforceNotSealed();
mDrawingOrderInParent = drawingOrderInParent;
}
@@ -2063,6 +2105,7 @@
* @return The collection info.
*/
public CollectionInfo getCollectionInfo() {
+ enforceNotRecycled();
return mCollectionInfo;
}
@@ -2078,6 +2121,7 @@
* @param collectionInfo The collection info.
*/
public void setCollectionInfo(CollectionInfo collectionInfo) {
+ enforceNotRecycled();
enforceNotSealed();
mCollectionInfo = collectionInfo;
}
@@ -2089,6 +2133,7 @@
* @return The collection item info.
*/
public CollectionItemInfo getCollectionItemInfo() {
+ enforceNotRecycled();
return mCollectionItemInfo;
}
@@ -2102,6 +2147,7 @@
* </p>
*/
public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
+ enforceNotRecycled();
enforceNotSealed();
mCollectionItemInfo = collectionItemInfo;
}
@@ -2112,6 +2158,7 @@
* @return The range.
*/
public RangeInfo getRangeInfo() {
+ enforceNotRecycled();
return mRangeInfo;
}
@@ -2126,6 +2173,7 @@
* @param rangeInfo The range info.
*/
public void setRangeInfo(RangeInfo rangeInfo) {
+ enforceNotRecycled();
enforceNotSealed();
mRangeInfo = rangeInfo;
}
@@ -2198,6 +2246,7 @@
* @see android.view.View#getAccessibilityLiveRegion()
*/
public int getLiveRegion() {
+ enforceNotRecycled();
return mLiveRegion;
}
@@ -2214,6 +2263,7 @@
* @see android.view.View#setAccessibilityLiveRegion(int)
*/
public void setLiveRegion(int mode) {
+ enforceNotRecycled();
enforceNotSealed();
mLiveRegion = mode;
}
@@ -2261,7 +2311,6 @@
* @param opensPopup If the the node opens a popup.
*/
public void setCanOpenPopup(boolean opensPopup) {
- enforceNotSealed();
setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
}
@@ -2348,6 +2397,7 @@
* @return The package name.
*/
public CharSequence getPackageName() {
+ enforceNotRecycled();
return mPackageName;
}
@@ -2364,6 +2414,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setPackageName(CharSequence packageName) {
+ enforceNotRecycled();
enforceNotSealed();
mPackageName = packageName;
}
@@ -2374,6 +2425,7 @@
* @return The class name.
*/
public CharSequence getClassName() {
+ enforceNotRecycled();
return mClassName;
}
@@ -2390,6 +2442,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setClassName(CharSequence className) {
+ enforceNotRecycled();
enforceNotSealed();
mClassName = className;
}
@@ -2413,6 +2466,7 @@
* @return The text.
*/
public CharSequence getText() {
+ enforceNotRecycled();
// Attach this node to any spans that need it
if (mText instanceof Spanned) {
Spanned spanned = (Spanned) mText;
@@ -2435,6 +2489,7 @@
* @hide
*/
public CharSequence getOriginalText() {
+ enforceNotRecycled();
return mOriginalText;
}
@@ -2451,6 +2506,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setText(CharSequence text) {
+ enforceNotRecycled();
enforceNotSealed();
mOriginalText = text;
// Replace any ClickableSpans in mText with placeholders
@@ -2489,6 +2545,7 @@
* @return The hint text.
*/
public CharSequence getHintText() {
+ enforceNotRecycled();
return mHintText;
}
@@ -2505,6 +2562,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setHintText(CharSequence hintText) {
+ enforceNotRecycled();
enforceNotSealed();
mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length());
}
@@ -2522,6 +2580,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setError(CharSequence error) {
+ enforceNotRecycled();
enforceNotSealed();
mError = (error == null) ? null : error.subSequence(0, error.length());
}
@@ -2532,6 +2591,7 @@
* @return The error text.
*/
public CharSequence getError() {
+ enforceNotRecycled();
return mError;
}
@@ -2541,6 +2601,7 @@
* @return The content description.
*/
public CharSequence getContentDescription() {
+ enforceNotRecycled();
return mContentDescription;
}
@@ -2557,6 +2618,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setContentDescription(CharSequence contentDescription) {
+ enforceNotRecycled();
enforceNotSealed();
mContentDescription = (contentDescription == null) ? null
: contentDescription.subSequence(0, contentDescription.length());
@@ -2569,6 +2631,7 @@
* @param labeled The view for which this info serves as a label.
*/
public void setLabelFor(View labeled) {
+ enforceNotRecycled();
setLabelFor(labeled, AccessibilityNodeProvider.HOST_VIEW_ID);
}
@@ -2592,6 +2655,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setLabelFor(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
final int rootAccessibilityViewId = (root != null)
? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
@@ -2610,6 +2674,7 @@
* @return The labeled info.
*/
public AccessibilityNodeInfo getLabelFor() {
+ enforceNotRecycled();
enforceSealed();
return getNodeForAccessibilityId(mLabelForId);
}
@@ -2644,6 +2709,7 @@
* @param virtualDescendantId The id of the virtual descendant.
*/
public void setLabeledBy(View root, int virtualDescendantId) {
+ enforceNotRecycled();
enforceNotSealed();
final int rootAccessibilityViewId = (root != null)
? root.getAccessibilityViewId() : UNDEFINED_ITEM_ID;
@@ -2662,6 +2728,7 @@
* @return The label.
*/
public AccessibilityNodeInfo getLabeledBy() {
+ enforceNotRecycled();
enforceSealed();
return getNodeForAccessibilityId(mLabeledById);
}
@@ -2678,6 +2745,7 @@
* @param viewIdResName The id resource name.
*/
public void setViewIdResourceName(String viewIdResName) {
+ enforceNotRecycled();
enforceNotSealed();
mViewIdResourceName = viewIdResName;
}
@@ -2695,6 +2763,7 @@
* @return The id resource name.
*/
public String getViewIdResourceName() {
+ enforceNotRecycled();
return mViewIdResourceName;
}
@@ -2710,6 +2779,7 @@
* there is no text selection and no cursor.
*/
public int getTextSelectionStart() {
+ enforceNotRecycled();
return mTextSelectionStart;
}
@@ -2725,6 +2795,7 @@
* there is no text selection and no cursor.
*/
public int getTextSelectionEnd() {
+ enforceNotRecycled();
return mTextSelectionEnd;
}
@@ -2742,6 +2813,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setTextSelection(int start, int end) {
+ enforceNotRecycled();
enforceNotSealed();
mTextSelectionStart = start;
mTextSelectionEnd = end;
@@ -2753,6 +2825,7 @@
* @return The input type.
*/
public int getInputType() {
+ enforceNotRecycled();
return mInputType;
}
@@ -2770,6 +2843,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void setInputType(int inputType) {
+ enforceNotRecycled();
enforceNotSealed();
mInputType = inputType;
}
@@ -2788,6 +2862,7 @@
* @return The bundle.
*/
public Bundle getExtras() {
+ enforceNotRecycled();
if (mExtras == null) {
mExtras = new Bundle();
}
@@ -2809,6 +2884,7 @@
* @return The value.
*/
private boolean getBooleanProperty(int property) {
+ enforceNotRecycled();
return (mBooleanProperties & property) != 0;
}
@@ -2821,6 +2897,7 @@
* @throws IllegalStateException If called from an AccessibilityService.
*/
private void setBooleanProperty(int property, boolean value) {
+ enforceNotRecycled();
enforceNotSealed();
if (value) {
mBooleanProperties |= property;
@@ -2850,6 +2927,7 @@
* @hide
*/
public int getConnectionId() {
+ enforceNotRecycled();
return mConnectionId;
}
@@ -2870,6 +2948,7 @@
* @hide
*/
public void setSourceNodeId(long sourceId, int windowId) {
+ enforceNotRecycled();
enforceNotSealed();
mSourceNodeId = sourceId;
mWindowId = windowId;
@@ -2883,6 +2962,7 @@
* @hide
*/
public long getSourceNodeId() {
+ enforceNotRecycled();
return mSourceNodeId;
}
@@ -2894,6 +2974,7 @@
* @hide
*/
public void setSealed(boolean sealed) {
+ enforceNotRecycled();
mSealed = sealed;
}
@@ -2960,6 +3041,11 @@
}
}
+ private void enforceNotRecycled() {
+ if (mRecycled) {
+ throw new IllegalStateException("Cannot interact with recycled instance");
+ }
+ }
/**
* Returns a cached instance if such is available otherwise a new one
* and sets the source.
@@ -3001,7 +3087,11 @@
if (sNumInstancesInUse != null) {
sNumInstancesInUse.incrementAndGet();
}
- return (info != null) ? info : new AccessibilityNodeInfo();
+ if (info != null) {
+ info.mRecycled = false;
+ return info;
+ }
+ return new AccessibilityNodeInfo();
}
/**
@@ -3027,6 +3117,7 @@
*/
public void recycle() {
clear();
+ mRecycled = true;
sPool.release(this);
if (sNumInstancesInUse != null) {
sNumInstancesInUse.decrementAndGet();
@@ -3052,6 +3143,7 @@
*/
@Override
public void writeToParcel(Parcel parcel, int flags) {
+ enforceNotRecycled();
// Write bit set of indices of fields with values differing from default
long nonDefaultFields = 0;
int fieldIndex = 0; // index of the current field
@@ -3286,6 +3378,7 @@
* @param other The other instance.
*/
private void init(AccessibilityNodeInfo other) {
+ enforceNotRecycled();
mSealed = other.mSealed;
mSourceNodeId = other.mSourceNodeId;
mParentNodeId = other.mParentNodeId;
@@ -3357,6 +3450,7 @@
* @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
*/
private void initFromParcel(Parcel parcel) {
+ enforceNotRecycled();
// Bit mask of non-default-valued field indices
long nonDefaultFields = parcel.readLong();
int fieldIndex = 0;