summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2013-06-06 14:09:10 -0700
committerSvetoslav <svetoslavganov@google.com>2013-06-18 10:41:48 -0700
commit3577a283e1af3e14fe980c4fec55781a58cd8e3c (patch)
tree61a5ec102df69ffe8980142398b5c944cd31f589
parentb31e370a941e8ed4e6393f32fa5356c8c84efa7a (diff)
downloadframeworks_base-3577a283e1af3e14fe980c4fec55781a58cd8e3c.zip
frameworks_base-3577a283e1af3e14fe980c4fec55781a58cd8e3c.tar.gz
frameworks_base-3577a283e1af3e14fe980c4fec55781a58cd8e3c.tar.bz2
Adding traits APIs to AccessibilityNodeInfo.
This change adds several traits and properties to AccessibilityNodeInfo aiming to allow better description of native Android components to accessibility services as well as mapping web content to native Android node info tree. Change-Id: I36b893cbaa6213c9d02d805e9dc36b6d792b4961
-rw-r--r--api/current.txt50
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java663
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java5
3 files changed, 716 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt
index 7484e70..94fa35f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27578,13 +27578,17 @@ package android.view.accessibility {
method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
method public int getChildCount();
method public java.lang.CharSequence getClassName();
+ method public android.view.accessibility.AccessibilityNodeInfo.CollectionInfo getCollectionInfo();
+ method public android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo getCollectionItemInfo();
method public java.lang.CharSequence getContentDescription();
method public int getInputType();
method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
method public int getMovementGranularities();
+ method public boolean getOpensPopup();
method public java.lang.CharSequence getPackageName();
method public android.view.accessibility.AccessibilityNodeInfo getParent();
+ method public android.view.accessibility.AccessibilityNodeInfo.RangeInfo getRangeInfo();
method public java.lang.CharSequence getText();
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
@@ -27594,11 +27598,17 @@ package android.view.accessibility {
method public boolean isCheckable();
method public boolean isChecked();
method public boolean isClickable();
+ method public boolean isContentInvalid();
+ method public boolean isDismissable();
method public boolean isEditable();
method public boolean isEnabled();
+ method public boolean isExpandable();
+ method public boolean isExpanded();
method public boolean isFocusable();
method public boolean isFocused();
+ method public boolean isLiveRegion();
method public boolean isLongClickable();
+ method public boolean isMultiLine();
method public boolean isPassword();
method public boolean isScrollable();
method public boolean isSelected();
@@ -27618,9 +27628,15 @@ package android.view.accessibility {
method public void setChecked(boolean);
method public void setClassName(java.lang.CharSequence);
method public void setClickable(boolean);
+ method public void setCollectionInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionInfo);
+ method public void setCollectionItemInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo);
method public void setContentDescription(java.lang.CharSequence);
+ method public void setContentInvalid(boolean);
+ method public void setDismissable(boolean);
method public void setEditable(boolean);
method public void setEnabled(boolean);
+ method public void setExpandable(boolean);
+ method public void setExpanded(boolean);
method public void setFocusable(boolean);
method public void setFocused(boolean);
method public void setInputType(int);
@@ -27628,12 +27644,16 @@ package android.view.accessibility {
method public void setLabelFor(android.view.View, int);
method public void setLabeledBy(android.view.View);
method public void setLabeledBy(android.view.View, int);
+ method public void setLiveRegion(boolean);
method public void setLongClickable(boolean);
method public void setMovementGranularities(int);
+ method public void setMultiLine(boolean);
+ method public void setOpensPopup(boolean);
method public void setPackageName(java.lang.CharSequence);
method public void setParent(android.view.View);
method public void setParent(android.view.View, int);
method public void setPassword(boolean);
+ method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
method public void setScrollable(boolean);
method public void setSelected(boolean);
method public void setSource(android.view.View);
@@ -27653,8 +27673,11 @@ package android.view.accessibility {
field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
field public static final int ACTION_CLICK = 16; // 0x10
+ field public static final int ACTION_COLLAPSE = 524288; // 0x80000
field public static final int ACTION_COPY = 16384; // 0x4000
field public static final int ACTION_CUT = 65536; // 0x10000
+ field public static final int ACTION_DISMISS = 1048576; // 0x100000
+ field public static final int ACTION_EXPAND = 262144; // 0x40000
field public static final int ACTION_FOCUS = 1; // 0x1
field public static final int ACTION_LONG_CLICK = 32; // 0x20
field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
@@ -27676,6 +27699,33 @@ package android.view.accessibility {
field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
}
+ public static final class AccessibilityNodeInfo.CollectionInfo {
+ method public int getHorizontalSize();
+ method public int getVerticalSize();
+ method public boolean isHierarchical();
+ method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
+ }
+
+ public static final class AccessibilityNodeInfo.CollectionItemInfo {
+ method public int getHorizontalPosition();
+ method public int getHorizontalSpan();
+ method public int getVerticalPosition();
+ method public int getVerticalSpan();
+ method public boolean isHeading();
+ method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
+ }
+
+ public static final class AccessibilityNodeInfo.RangeInfo {
+ method public float getCurrent();
+ method public float getMax();
+ method public float getMin();
+ method public int getType();
+ method public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float);
+ field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+ field public static final int RANGE_TYPE_INT = 0; // 0x0
+ field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+ }
+
public abstract class AccessibilityNodeProvider {
ctor public AccessibilityNodeProvider();
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo(int);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 750e022..8caa283 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -268,6 +268,23 @@ public class AccessibilityNodeInfo implements Parcelable {
public static final int ACTION_SET_SELECTION = 0x00020000;
/**
+ * Action to expand an expandable node.
+ */
+ public static final int ACTION_EXPAND = 0x00040000;
+
+ /**
+ * Action to collapse an expandable node.
+ */
+ public static final int ACTION_COLLAPSE = 0x00080000;
+
+ /**
+ * Action to dismiss a dismissable node.
+ */
+ public static final int ACTION_DISMISS = 0x00100000;
+
+ // Action arguments
+
+ /**
* Argument for which movement granularity to be used when traversing the node text.
* <p>
* <strong>Type:</strong> int<br>
@@ -334,6 +351,8 @@ public class AccessibilityNodeInfo implements Parcelable {
public static final String ACTION_ARGUMENT_SELECTION_END_INT =
"ACTION_ARGUMENT_SELECTION_END_INT";
+ // Focus types
+
/**
* The input focus.
*/
@@ -399,6 +418,20 @@ public class AccessibilityNodeInfo implements Parcelable {
private static final int BOOLEAN_PROPERTY_EDITABLE = 0x00001000;
+ private static final int BOOLEAN_PROPERTY_LIVE_REGION = 0x00002000;
+
+ private static final int BOOLEAN_PROPERTY_OPENS_POPUP = 0x00004000;
+
+ private static final int BOOLEAN_PROPERTY_EXPANDABLE = 0x00008000;
+
+ private static final int BOOLEAN_PROPERTY_EXPANDED = 0x00010000;
+
+ private static final int BOOLEAN_PROPERTY_DISMISSABLE = 0x00020000;
+
+ private static final int BOOLEAN_PROPERTY_MULTI_LINE = 0x00040000;
+
+ private static final int BOOLEAN_PROPERTY_CONTENT_INVALID = 0x00080000;
+
/**
* Bits that provide the id of a virtual descendant of a view.
*/
@@ -489,6 +522,10 @@ public class AccessibilityNodeInfo implements Parcelable {
private int mConnectionId = UNDEFINED;
+ private RangeInfo mRangeInfo;
+ private CollectionInfo mCollectionInfo;
+ private CollectionItemInfo mCollectionItemInfo;
+
/**
* Hide constructor from clients.
*/
@@ -1334,6 +1371,255 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Gets the collection info if the node is a collection. A collection
+ * child is always a collection item.
+ *
+ * @return The collection info.
+ */
+ public CollectionInfo getCollectionInfo() {
+ return mCollectionInfo;
+ }
+
+ /**
+ * Sets the collection info if the node is a collection. A collection
+ * child is always a collection item.
+ * <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 collectionInfo The collection info.
+ */
+ public void setCollectionInfo(CollectionInfo collectionInfo) {
+ enforceNotSealed();
+ mCollectionInfo = collectionInfo;
+ }
+
+ /**
+ * Gets the collection item info if the node is a collection item. A collection
+ * item is always a child of a collection.
+ *
+ * @return The collection item info.
+ */
+ public CollectionItemInfo getCollectionItemInfo() {
+ return mCollectionItemInfo;
+ }
+
+ /**
+ * Sets the collection item info if the node is a collection item. A collection
+ * item is always a child of a collection.
+ * <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>
+ *
+ * @return collectionItem True if the node is an item.
+ */
+ public void setCollectionItemInfo(CollectionItemInfo collectionItemInfo) {
+ enforceNotSealed();
+ mCollectionItemInfo = collectionItemInfo;
+ }
+
+ /**
+ * Gets the range info if this node is a range.
+ *
+ * @return The range.
+ */
+ public RangeInfo getRangeInfo() {
+ return mRangeInfo;
+ }
+
+ /**
+ * Sets the range info if this node is a range.
+ * <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 rangeInfo The range info.
+ */
+ public void setRangeInfo(RangeInfo rangeInfo) {
+ enforceNotSealed();
+ mRangeInfo = rangeInfo;
+ }
+
+ /**
+ * Gets if the content of this node is invalid. For example,
+ * a date is not well-formed.
+ *
+ * @return If the node content is invalid.
+ */
+ public boolean isContentInvalid() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID);
+ }
+
+ /**
+ * Sets if the content of this node is invalid. For example,
+ * a date is not well-formed.
+ * <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 contentInvalid If the node content is invalid.
+ */
+ public void setContentInvalid(boolean contentInvalid) {
+ setBooleanProperty(BOOLEAN_PROPERTY_CONTENT_INVALID, contentInvalid);
+ }
+
+ /**
+ * Gets if the node is a live region for whose changes the user
+ * should be notified. It is the responsibility of the accessibility
+ * service to monitor this region and notify the user if it changes.
+ *
+ * @return If the node is a live region.
+ */
+ public boolean isLiveRegion() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_LIVE_REGION);
+ }
+
+ /**
+ * Sets if the node is a live region for whose changes the user
+ * should be notified. It is the responsibility of the accessibility
+ * service to monitor this region and notify the user if it changes.
+ * <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 liveRegion If the node is a live region.
+ */
+ public void setLiveRegion(boolean liveRegion) {
+ enforceNotSealed();
+ setBooleanProperty(BOOLEAN_PROPERTY_LIVE_REGION, liveRegion);
+ }
+
+ /**
+ * Gets if the node is a multi line editable text.
+ *
+ * @return True if the node is multi line.
+ */
+ public boolean isMultiLine() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE);
+ }
+
+ /**
+ * Sets if the node is a multi line editable text.
+ * <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 multiLine True if the node is multi line.
+ */
+ public void setMultiLine(boolean multiLine) {
+ enforceNotSealed();
+ setBooleanProperty(BOOLEAN_PROPERTY_MULTI_LINE, multiLine);
+ }
+
+ /**
+ * Gets if this node opens a popup or a dialog.
+ *
+ * @return If the the node opens a popup.
+ */
+ public boolean getOpensPopup() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP);
+ }
+
+ /**
+ * Sets if this node opens a popup or a dialog.
+ * <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 opensPopup If the the node opens a popup.
+ */
+ public void setOpensPopup(boolean opensPopup) {
+ enforceNotSealed();
+ setBooleanProperty(BOOLEAN_PROPERTY_OPENS_POPUP, opensPopup);
+ }
+
+ /**
+ * Gets if the node can be expanded.
+ *
+ * @return If the node can be expanded.
+ */
+ public boolean isExpandable() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_EXPANDABLE);
+ }
+
+ /**
+ * Sets if the node can be expanded.
+ * <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 expandable If the node can be expanded.
+ */
+ public void setExpandable(boolean expandable) {
+ enforceNotSealed();
+ setBooleanProperty(BOOLEAN_PROPERTY_EXPANDABLE, expandable);
+ }
+
+ /**
+ * Gets if the node is expanded.
+ *
+ * @return If the node is expanded.
+ */
+ public boolean isExpanded() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_EXPANDED);
+ }
+
+ /**
+ * Sets if the node is expanded.
+ * <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 expanded If the node is expanded.
+ */
+ public void setExpanded(boolean expanded) {
+ enforceNotSealed();
+ setBooleanProperty(BOOLEAN_PROPERTY_EXPANDED, expanded);
+ }
+
+ /**
+ * Gets if the node can be dismissed.
+ *
+ * @return If the node can be dismissed.
+ */
+ public boolean isDismissable() {
+ return getBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE);
+ }
+
+ /**
+ * Sets if the node can be dismissed.
+ * <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 dismissable If the node can be dismissed.
+ */
+ public void setDismissable(boolean dismissable) {
+ enforceNotSealed();
+ setBooleanProperty(BOOLEAN_PROPERTY_DISMISSABLE, dismissable);
+ }
+
+ /**
* Gets the package this node comes from.
*
* @return The package name.
@@ -1921,6 +2207,36 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.writeInt(0);
}
+ if (mRangeInfo != null) {
+ parcel.writeInt(1);
+ parcel.writeInt(mRangeInfo.getType());
+ parcel.writeFloat(mRangeInfo.getMin());
+ parcel.writeFloat(mRangeInfo.getMax());
+ parcel.writeFloat(mRangeInfo.getCurrent());
+ } else {
+ parcel.writeInt(0);
+ }
+
+ if (mCollectionInfo != null) {
+ parcel.writeInt(1);
+ parcel.writeInt(mCollectionInfo.getHorizontalSize());
+ parcel.writeInt(mCollectionInfo.getVerticalSize());
+ parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
+ } else {
+ parcel.writeInt(0);
+ }
+
+ if (mCollectionItemInfo != null) {
+ parcel.writeInt(1);
+ parcel.writeInt(mCollectionItemInfo.getHorizontalPosition());
+ parcel.writeInt(mCollectionItemInfo.getHorizontalSpan());
+ parcel.writeInt(mCollectionItemInfo.getVerticalPosition());
+ parcel.writeInt(mCollectionItemInfo.getVerticalSpan());
+ parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
+ } else {
+ parcel.writeInt(0);
+ }
+
// Since instances of this class are fetched via synchronous i.e. blocking
// calls in IPCs we always recycle as soon as the instance is marshaled.
recycle();
@@ -1951,7 +2267,7 @@ public class AccessibilityNodeInfo implements Parcelable {
mMovementGranularities = other.mMovementGranularities;
final int otherChildIdCount = other.mChildNodeIds.size();
for (int i = 0; i < otherChildIdCount; i++) {
- mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
+ mChildNodeIds.put(i, other.mChildNodeIds.valueAt(i));
}
mTextSelectionStart = other.mTextSelectionStart;
mTextSelectionEnd = other.mTextSelectionEnd;
@@ -1959,6 +2275,9 @@ public class AccessibilityNodeInfo implements Parcelable {
if (other.mBundle != null && !other.mBundle.isEmpty()) {
getBundle().putAll(other.mBundle);
}
+ mRangeInfo = other.mRangeInfo;
+ mCollectionInfo = other.mCollectionInfo;
+ mCollectionItemInfo = other.mCollectionItemInfo;
}
/**
@@ -2006,11 +2325,36 @@ public class AccessibilityNodeInfo implements Parcelable {
mTextSelectionStart = parcel.readInt();
mTextSelectionEnd = parcel.readInt();
+
mInputType = parcel.readInt();
if (parcel.readInt() == 1) {
getBundle().putAll(parcel.readBundle());
}
+
+ if (parcel.readInt() == 1) {
+ mRangeInfo = RangeInfo.obtain(
+ parcel.readInt(),
+ parcel.readFloat(),
+ parcel.readFloat(),
+ parcel.readFloat());
+ }
+
+ if (parcel.readInt() == 1) {
+ mCollectionInfo = CollectionInfo.obtain(
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt() == 1);
+ }
+
+ if (parcel.readInt() == 1) {
+ mCollectionItemInfo = CollectionItemInfo.obtain(
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt(),
+ parcel.readInt() == 1);
+ }
}
/**
@@ -2041,6 +2385,18 @@ public class AccessibilityNodeInfo implements Parcelable {
if (mBundle != null) {
mBundle.clear();
}
+ if (mRangeInfo != null) {
+ mRangeInfo.recycle();
+ mRangeInfo = null;
+ }
+ if (mCollectionInfo != null) {
+ mCollectionInfo.recycle();
+ mCollectionInfo = null;
+ }
+ if (mCollectionItemInfo != null) {
+ mCollectionItemInfo.recycle();
+ mCollectionItemInfo = null;
+ }
}
/**
@@ -2220,6 +2576,311 @@ public class AccessibilityNodeInfo implements Parcelable {
}
/**
+ * Class with information if a node is a range. Use
+ * {@link #obtain(int, float, float, float)} to get an instance.
+ */
+ public static final class RangeInfo {
+ private static final int MAX_POOL_SIZE = 10;
+
+ /** Range type: integer. */
+ public static final int RANGE_TYPE_INT = 0;
+ /** Range type: float. */
+ public static final int RANGE_TYPE_FLOAT = 1;
+ /** Range type: percent with values from zero to one.*/
+ public static final int RANGE_TYPE_PERCENT = 2;
+
+ private static final SynchronizedPool<RangeInfo> sPool =
+ new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE);
+
+ private int mType;
+ private float mMin;
+ private float mMax;
+ private float mCurrent;
+
+ /**
+ * Obtains a pooled instance.
+ *
+ * @param type The type of the range.
+ * @param min The min value.
+ * @param max The max value.
+ * @param current The current value.
+ */
+ public static RangeInfo obtain(int type, float min, float max, float current) {
+ RangeInfo info = sPool.acquire();
+ return (info != null) ? info : new RangeInfo(type, min, max, current);
+ }
+
+ /**
+ * Creates a new range.
+ *
+ * @param type The type of the range.
+ * @param min The min value.
+ * @param max The max value.
+ * @param current The current value.
+ */
+ private RangeInfo(int type, float min, float max, float current) {
+ mType = type;
+ mMin = min;
+ mMax = max;
+ mCurrent = current;
+ }
+
+ /**
+ * Gets the range type.
+ *
+ * @return The range type.
+ *
+ * @see #RANGE_TYPE_INT
+ * @see #RANGE_TYPE_FLOAT
+ * @see #RANGE_TYPE_PERCENT
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Gets the min value.
+ *
+ * @return The min value.
+ */
+ public float getMin() {
+ return mMin;
+ }
+
+ /**
+ * Gets the max value.
+ *
+ * @return The max value.
+ */
+ public float getMax() {
+ return mMax;
+ }
+
+ /**
+ * Gets the current value.
+ *
+ * @return The current value.
+ */
+ public float getCurrent() {
+ return mCurrent;
+ }
+
+ /**
+ * Recycles this instance.
+ */
+ void recycle() {
+ clear();
+ sPool.release(this);
+ }
+
+ private void clear() {
+ mType = 0;
+ mMin = 0;
+ mMax = 0;
+ mCurrent = 0;
+ }
+ }
+
+ /**
+ * Class with information if a node is a collection. Use
+ * {@link #obtain(int, float, float, float)} to an instance.
+ */
+ public static final class CollectionInfo {
+ private static final int MAX_POOL_SIZE = 20;
+
+ private static final SynchronizedPool<CollectionInfo> sPool =
+ new SynchronizedPool<CollectionInfo>(MAX_POOL_SIZE);
+
+ private int mHorizontalSize;
+ private int mVerticalSize;
+ private boolean mHierarchical;
+
+ /**
+ * Obtains a pooled instance.
+ *
+ * @param horizontalSize The horizontal size.
+ * @param verticalSize The vertical size.
+ * @param hierarchical Whether the collection is hierarchical.
+ */
+ public static CollectionInfo obtain(int horizontalSize, int verticalSize,
+ boolean hierarchical) {
+ CollectionInfo info = sPool.acquire();
+ return (info != null) ? info : new CollectionInfo(horizontalSize,
+ verticalSize, hierarchical);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param horizontalSize The horizontal size.
+ * @param verticalSize The vertical size.
+ * @param hierarchical Whether the collection is hierarchical.
+ */
+ private CollectionInfo(int horizontalSize, int verticalSize,
+ boolean hierarchical) {
+ mHorizontalSize = horizontalSize;
+ mVerticalSize = verticalSize;
+ mHierarchical = hierarchical;
+ }
+
+ /**
+ * Gets the horizontal size in terms of item positions.
+ *
+ * @return The size.
+ */
+ public int getHorizontalSize() {
+ return mHorizontalSize;
+ }
+
+ /**
+ * Gets the vertical size in terms of item positions.
+ *
+ * @return The size.
+ */
+ public int getVerticalSize() {
+ return mVerticalSize;
+ }
+
+ /**
+ * Gets if the collection is a hierarchically ordered.
+ *
+ * @return Whether the collection is hierarchical.
+ */
+ public boolean isHierarchical() {
+ return mHierarchical;
+ }
+
+ /**
+ * Recycles this instance.
+ */
+ void recycle() {
+ clear();
+ sPool.release(this);
+ }
+
+ private void clear() {
+ mHorizontalSize = 0;
+ mVerticalSize = 0;
+ mHierarchical = false;
+ }
+ }
+
+ /**
+ * Class with information if a node is a collection item. Use
+ * {@link #obtain(int, int, boolean)} to get an instance.
+ */
+ public static final class CollectionItemInfo {
+ private static final int MAX_POOL_SIZE = 20;
+
+ private static final SynchronizedPool<CollectionItemInfo> sPool =
+ new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
+
+ /**
+ * Obtains a pooled instance.
+ *
+ * @param horizontalPosition The horizontal item position.
+ * @param horizontalSpan The horizontal item span.
+ * @param verticalPosition The vertical item position.
+ * @param verticalSpan The vertical item span.
+ * @param heading Whether the item is a heading.
+ */
+ public static CollectionItemInfo obtain(int horizontalPosition, int horizontalSpan,
+ int verticalPosition, int verticalSpan, boolean heading) {
+ CollectionItemInfo info = sPool.acquire();
+ return (info != null) ? info : new CollectionItemInfo(horizontalPosition,
+ horizontalSpan, verticalPosition, verticalSpan, heading);
+ }
+
+ private boolean mHeading;
+ private int mHorizontalPosition;
+ private int mVerticalPosition;
+ private int mHorizontalSpan;
+ private int mVerticalSpan;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param horizontalPosition The horizontal item position.
+ * @param horizontalSpan The horizontal item span.
+ * @param verticalPosition The vertical item position.
+ * @param verticalSpan The vertical item span.
+ * @param heading Whether the item is a heading.
+ */
+ private CollectionItemInfo(int horizontalPosition, int horizontalSpan,
+ int verticalPosition, int verticalSpan, boolean heading) {
+ mHorizontalPosition = horizontalPosition;
+ mHorizontalSpan = horizontalSpan;
+ mVerticalPosition = verticalPosition;
+ mVerticalSpan = verticalSpan;
+ mHeading = heading;
+ }
+
+ /**
+ * Gets the horizontal item position in the parent collection.
+ *
+ * @return The position.
+ */
+ public int getHorizontalPosition() {
+ return mHorizontalPosition;
+ }
+
+ /**
+ * Gets the vertical item position in the parent collection.
+ *
+ * @return The position.
+ */
+ public int getVerticalPosition() {
+ return mVerticalPosition;
+ }
+
+ /**
+ * Gets the horizontal span in terms of item positions
+ * of the parent collection.
+ *
+ * @return The span.
+ */
+ public int getHorizontalSpan() {
+ return mHorizontalSpan;
+ }
+
+ /**
+ * Gets the vertical span in terms of item positions
+ * of the parent collection.
+ *
+ * @return The span.
+ */
+ public int getVerticalSpan() {
+ return mVerticalSpan;
+ }
+
+ /**
+ * Gets if the collection item is a heading. For example, section
+ * heading, table header, etc.
+ *
+ * @return If the item is a heading.
+ */
+ public boolean isHeading() {
+ return mHeading;
+ }
+
+ /**
+ * Recycles this instance.
+ */
+ void recycle() {
+ clear();
+ sPool.release(this);
+ }
+
+ private void clear() {
+ mHorizontalPosition = 0;
+ mHorizontalSpan = 0;
+ mVerticalPosition = 0;
+ mVerticalSpan = 0;
+ mHeading = false;
+ }
+ }
+
+ /**
* @see Parcelable.Creator
*/
public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2f8250f..0ab56df 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2685,7 +2685,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
| AccessibilityNodeInfo.ACTION_COPY
| AccessibilityNodeInfo.ACTION_PASTE
| AccessibilityNodeInfo.ACTION_CUT
- | AccessibilityNodeInfo.ACTION_SET_SELECTION;
+ | AccessibilityNodeInfo.ACTION_SET_SELECTION
+ | AccessibilityNodeInfo.ACTION_EXPAND
+ | AccessibilityNodeInfo.ACTION_COLLAPSE
+ | AccessibilityNodeInfo.ACTION_DISMISS;
private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
AccessibilityEvent.TYPE_VIEW_CLICKED