summaryrefslogtreecommitdiffstats
path: root/core/java/android/view/accessibility
diff options
context:
space:
mode:
authorAlan Viverette <alanv@google.com>2013-11-06 15:33:03 -0800
committerAlan Viverette <alanv@google.com>2013-11-06 15:33:03 -0800
commitf0aed09ed8153043e40b3ac99788d47ba0831306 (patch)
tree8fc4ca8705ff46b8f2ce6500bd6c975163d9c6b7 /core/java/android/view/accessibility
parentb92fd5d893548cfae71f5efda6d4f1e46004e5da (diff)
downloadframeworks_base-f0aed09ed8153043e40b3ac99788d47ba0831306.zip
frameworks_base-f0aed09ed8153043e40b3ac99788d47ba0831306.tar.gz
frameworks_base-f0aed09ed8153043e40b3ac99788d47ba0831306.tar.bz2
Add methods for removing children and actions from A11y nodes
BUG: 11421730 Change-Id: Ide396e6a0fec871395a9cadf8880c16d0de08294
Diffstat (limited to 'core/java/android/view/accessibility')
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java5
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java178
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfoCache.java23
3 files changed, 162 insertions, 44 deletions
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 139df3e..d6e40aec 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -718,10 +718,9 @@ public final class AccessibilityInteractionClient
Log.e(LOG_TAG, "Duplicate node.");
return;
}
- SparseLongArray childIds = current.getChildNodeIds();
- final int childCount = childIds.size();
+ final int childCount = current.getChildCount();
for (int i = 0; i < childCount; i++) {
- final long childId = childIds.valueAt(i);
+ final long childId = current.getChildId(i);
for (int j = 0; j < infoCount; j++) {
AccessibilityNodeInfo child = infos.get(j);
if (child.getSourceNodeId() == childId) {
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4f53c1e..61aabea 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -22,8 +22,8 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.InputType;
+import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
-import android.util.SparseLongArray;
import android.view.View;
import java.util.Collections;
@@ -503,7 +503,7 @@ public class AccessibilityNodeInfo implements Parcelable {
private CharSequence mContentDescription;
private String mViewIdResourceName;
- private final SparseLongArray mChildNodeIds = new SparseLongArray();
+ private LongArray mChildNodeIds;
private int mActions;
private int mMovementGranularities;
@@ -666,21 +666,35 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * @return The ids of the children.
+ * Returns the array containing the IDs of this node's children.
*
* @hide
*/
- public SparseLongArray getChildNodeIds() {
+ public LongArray getChildNodeIds() {
return mChildNodeIds;
}
/**
+ * Returns the id of the child at the specified index.
+ *
+ * @throws IndexOutOfBoundsException when index &lt; 0 || index &gt;=
+ * getChildCount()
+ * @hide
+ */
+ public long getChildId(int index) {
+ if (mChildNodeIds == null) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mChildNodeIds.get(index);
+ }
+
+ /**
* Gets the number of children.
*
* @return The child count.
*/
public int getChildCount() {
- return mChildNodeIds.size();
+ return mChildNodeIds == null ? 0 : mChildNodeIds.size();
}
/**
@@ -699,6 +713,9 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public AccessibilityNodeInfo getChild(int index) {
enforceSealed();
+ if (mChildNodeIds == null) {
+ return null;
+ }
if (!canPerformRequestOverConnection(mSourceNodeId)) {
return null;
}
@@ -721,7 +738,35 @@ public class AccessibilityNodeInfo implements Parcelable {
* @throws IllegalStateException If called from an AccessibilityService.
*/
public void addChild(View child) {
- addChild(child, UNDEFINED);
+ addChildInternal(child, UNDEFINED, true);
+ }
+
+ /**
+ * Unchecked version of {@link #addChild(View)} that does not verify
+ * uniqueness. For framework use only.
+ *
+ * @hide
+ */
+ public void addChildUnchecked(View child) {
+ addChildInternal(child, UNDEFINED, false);
+ }
+
+ /**
+ * Removes a child. If the child was not previously added to the node,
+ * calling this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param child The child.
+ * @return true if the child was present
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public boolean removeChild(View child) {
+ return removeChild(child, UNDEFINED);
}
/**
@@ -739,12 +784,49 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param virtualDescendantId The id of the virtual child.
*/
public void addChild(View root, int virtualDescendantId) {
+ addChildInternal(root, virtualDescendantId, true);
+ }
+
+ private void addChildInternal(View root, int virtualDescendantId, boolean checked) {
enforceNotSealed();
- final int index = mChildNodeIds.size();
+ if (mChildNodeIds == null) {
+ mChildNodeIds = new LongArray();
+ }
final int rootAccessibilityViewId =
(root != null) ? root.getAccessibilityViewId() : UNDEFINED;
final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
- mChildNodeIds.put(index, childNodeId);
+ // If we're checking uniqueness and the ID already exists, abort.
+ if (checked && mChildNodeIds.indexOf(childNodeId) >= 0) {
+ return;
+ }
+ mChildNodeIds.add(childNodeId);
+ }
+
+ /**
+ * Removes a virtual child which is a descendant of the given
+ * <code>root</code>. If the child was not previously added to the node,
+ * calling this method has no effect.
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual child.
+ * @return true if the child was present
+ * @see #addChild(View, int)
+ */
+ public boolean removeChild(View root, int virtualDescendantId) {
+ enforceNotSealed();
+ final LongArray childIds = mChildNodeIds;
+ if (childIds == null) {
+ return false;
+ }
+ final int rootAccessibilityViewId =
+ (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
+ final long childNodeId = makeNodeId(rootAccessibilityViewId, virtualDescendantId);
+ final int index = childIds.indexOf(childNodeId);
+ if (index < 0) {
+ return false;
+ }
+ childIds.remove(index);
+ return true;
}
/**
@@ -789,6 +871,24 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Removes an action that can be performed on the node. If the action was
+ * not already added to the node, calling this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
+ *
+ * @param action The action.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void removeAction(int action) {
+ enforceNotSealed();
+ mActions &= ~action;
+ }
+
+ /**
* Sets the movement granularities for traversing the text of this node.
* <p>
* <strong>Note:</strong> Cannot be called from an
@@ -1408,8 +1508,6 @@ public class AccessibilityNodeInfo implements Parcelable {
* {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
- *
- * @return collectionItem True if the node is an item.
*/
public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
enforceNotSealed();
@@ -1951,6 +2049,7 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* {@inheritDoc}
*/
+ @Override
public int describeContents() {
return 0;
}
@@ -2114,6 +2213,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* is recycled. You must not touch the object after calling this function.
* </p>
*/
+ @Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(isSealed() ? 1 : 0);
parcel.writeLong(mSourceNodeId);
@@ -2123,11 +2223,15 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeLong(mLabeledById);
parcel.writeInt(mConnectionId);
- SparseLongArray childIds = mChildNodeIds;
- final int childIdsSize = childIds.size();
- parcel.writeInt(childIdsSize);
- for (int i = 0; i < childIdsSize; i++) {
- parcel.writeLong(childIds.valueAt(i));
+ final LongArray childIds = mChildNodeIds;
+ if (childIds == null) {
+ parcel.writeInt(0);
+ } else {
+ final int childIdsSize = childIds.size();
+ parcel.writeInt(childIdsSize);
+ for (int i = 0; i < childIdsSize; i++) {
+ parcel.writeLong(childIds.get(i));
+ }
}
parcel.writeInt(mBoundsInParent.top);
@@ -2222,10 +2326,16 @@ public class AccessibilityNodeInfo implements Parcelable {
mActions= other.mActions;
mBooleanProperties = other.mBooleanProperties;
mMovementGranularities = other.mMovementGranularities;
- final int otherChildIdCount = other.mChildNodeIds.size();
- for (int i = 0; i < otherChildIdCount; i++) {
- mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
+
+ final LongArray otherChildNodeIds = other.mChildNodeIds;
+ if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) {
+ if (mChildNodeIds == null) {
+ mChildNodeIds = otherChildNodeIds.clone();
+ } else {
+ mChildNodeIds.addAll(otherChildNodeIds);
+ }
}
+
mTextSelectionStart = other.mTextSelectionStart;
mTextSelectionEnd = other.mTextSelectionEnd;
mInputType = other.mInputType;
@@ -2255,11 +2365,15 @@ public class AccessibilityNodeInfo implements Parcelable {
mLabeledById = parcel.readLong();
mConnectionId = parcel.readInt();
- SparseLongArray childIds = mChildNodeIds;
final int childrenSize = parcel.readInt();
- for (int i = 0; i < childrenSize; i++) {
- final long childId = parcel.readLong();
- childIds.put(i, childId);
+ if (childrenSize <= 0) {
+ mChildNodeIds = null;
+ } else {
+ mChildNodeIds = new LongArray(childrenSize);
+ for (int i = 0; i < childrenSize; i++) {
+ final long childId = parcel.readLong();
+ mChildNodeIds.add(childId);
+ }
}
mBoundsInParent.top = parcel.readInt();
@@ -2331,7 +2445,9 @@ public class AccessibilityNodeInfo implements Parcelable {
mWindowId = UNDEFINED;
mConnectionId = UNDEFINED;
mMovementGranularities = 0;
- mChildNodeIds.clear();
+ if (mChildNodeIds != null) {
+ mChildNodeIds.clear();
+ }
mBoundsInParent.set(0, 0, 0, 0);
mBoundsInScreen.set(0, 0, 0, 0);
mBooleanProperties = 0;
@@ -2493,12 +2609,14 @@ public class AccessibilityNodeInfo implements Parcelable {
}
builder.append("]");
- SparseLongArray childIds = mChildNodeIds;
builder.append("; childAccessibilityIds: [");
- for (int i = 0, count = childIds.size(); i < count; i++) {
- builder.append(childIds.valueAt(i));
- if (i < count - 1) {
- builder.append(", ");
+ final LongArray childIds = mChildNodeIds;
+ if (childIds != null) {
+ for (int i = 0, count = childIds.size(); i < count; i++) {
+ builder.append(childIds.get(i));
+ if (i < count - 1) {
+ builder.append(", ");
+ }
}
}
builder.append("]");
@@ -2893,16 +3011,18 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
- * @see Parcelable.Creator
+ * @see android.os.Parcelable.Creator
*/
public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
new Parcelable.Creator<AccessibilityNodeInfo>() {
+ @Override
public AccessibilityNodeInfo createFromParcel(Parcel parcel) {
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
info.initFromParcel(parcel);
return info;
}
+ @Override
public AccessibilityNodeInfo[] newArray(int size) {
return new AccessibilityNodeInfo[size];
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index a9473a8..85aca61 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -18,6 +18,7 @@ package android.view.accessibility;
import android.os.Build;
import android.util.Log;
+import android.util.LongArray;
import android.util.LongSparseArray;
import android.util.SparseLongArray;
@@ -172,12 +173,12 @@ public class AccessibilityNodeInfoCache {
// the new one represents a source state where some of the
// children have been removed to avoid having disconnected
// subtrees in the cache.
- SparseLongArray oldChildrenIds = oldInfo.getChildNodeIds();
- SparseLongArray newChildrenIds = info.getChildNodeIds();
- final int oldChildCount = oldChildrenIds.size();
+ // TODO: Runs in O(n^2), could optimize to O(n + n log n)
+ final LongArray newChildrenIds = info.getChildNodeIds();
+ final int oldChildCount = oldInfo.getChildCount();
for (int i = 0; i < oldChildCount; i++) {
- final long oldChildId = oldChildrenIds.valueAt(i);
- if (newChildrenIds.indexOfValue(oldChildId) < 0) {
+ final long oldChildId = oldInfo.getChildId(i);
+ if (newChildrenIds.indexOf(oldChildId) < 0) {
clearSubTreeLocked(oldChildId);
}
}
@@ -237,10 +238,9 @@ public class AccessibilityNodeInfoCache {
return;
}
mCacheImpl.remove(rootNodeId);
- SparseLongArray childNodeIds = current.getChildNodeIds();
- final int childCount = childNodeIds.size();
+ final int childCount = current.getChildCount();
for (int i = 0; i < childCount; i++) {
- final long childNodeId = childNodeIds.valueAt(i);
+ final long childNodeId = current.getChildId(i);
clearSubTreeRecursiveLocked(childNodeId);
}
}
@@ -301,11 +301,10 @@ public class AccessibilityNodeInfoCache {
}
}
- SparseLongArray childIds = current.getChildNodeIds();
- final int childCount = childIds.size();
+ final int childCount = current.getChildCount();
for (int i = 0; i < childCount; i++) {
- final long childId = childIds.valueAt(i);
- AccessibilityNodeInfo child = mCacheImpl.get(childId);
+ final long childId = current.getChildId(i);
+ final AccessibilityNodeInfo child = mCacheImpl.get(childId);
if (child != null) {
fringe.add(child);
}