diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 3bf8d27e86303..e63438c58ec89 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -336,7 +336,8 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public static final int ACTION_SET_TEXT = 0x00200000;
- private static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
+ /** @hide */
+ public static final int LAST_LEGACY_STANDARD_ACTION = ACTION_SET_TEXT;
/**
* Mask to see if the value is larger than the largest ACTION_ constant
@@ -1181,7 +1182,7 @@ public class AccessibilityNodeInfo implements Parcelable {
"actions: " + action);
}
- addLegacyStandardActions(action);
+ addStandardActions(action);
}
/**
@@ -3194,22 +3195,22 @@ public class AccessibilityNodeInfo implements Parcelable {
if (mActions != null && !mActions.isEmpty()) {
final int actionCount = mActions.size();
- int nonLegacyActionCount = 0;
- int defaultLegacyStandardActions = 0;
+ int nonStandardActionCount = 0;
+ int defaultStandardActions = 0;
for (int i = 0; i < actionCount; i++) {
AccessibilityAction action = mActions.get(i);
- if (isDefaultLegacyStandardAction(action)) {
- defaultLegacyStandardActions |= action.getId();
+ if (isDefaultStandardAction(action)) {
+ defaultStandardActions |= action.mSerializationFlag;
} else {
- nonLegacyActionCount++;
+ nonStandardActionCount++;
}
}
- parcel.writeInt(defaultLegacyStandardActions);
- parcel.writeInt(nonLegacyActionCount);
+ parcel.writeInt(defaultStandardActions);
+ parcel.writeInt(nonStandardActionCount);
for (int i = 0; i < actionCount; i++) {
AccessibilityAction action = mActions.get(i);
- if (!isDefaultLegacyStandardAction(action)) {
+ if (!isDefaultStandardAction(action)) {
parcel.writeInt(action.getId());
parcel.writeCharSequence(action.getLabel());
}
@@ -3401,10 +3402,10 @@ public class AccessibilityNodeInfo implements Parcelable {
}
if (isBitSet(nonDefaultFields, fieldIndex++)) {
- final int legacyStandardActions = parcel.readInt();
- addLegacyStandardActions(legacyStandardActions);
- final int nonLegacyActionCount = parcel.readInt();
- for (int i = 0; i < nonLegacyActionCount; i++) {
+ final int standardActions = parcel.readInt();
+ addStandardActions(standardActions);
+ final int nonStandardActionCount = parcel.readInt();
+ for (int i = 0; i < nonStandardActionCount; i++) {
final AccessibilityAction action = new AccessibilityAction(
parcel.readInt(), parcel.readCharSequence());
addActionUnchecked(action);
@@ -3479,9 +3480,8 @@ public class AccessibilityNodeInfo implements Parcelable {
init(DEFAULT);
}
- private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) {
- return (action.getId() <= LAST_LEGACY_STANDARD_ACTION
- && TextUtils.isEmpty(action.getLabel()));
+ private static boolean isDefaultStandardAction(AccessibilityAction action) {
+ return action.mSerializationFlag != -1 && TextUtils.isEmpty(action.getLabel());
}
private static AccessibilityAction getActionSingleton(int actionId) {
@@ -3496,12 +3496,24 @@ public class AccessibilityNodeInfo implements Parcelable {
return null;
}
- private void addLegacyStandardActions(int actionMask) {
- int remainingIds = actionMask;
+ private static AccessibilityAction getActionSingletonBySerializationFlag(int flag) {
+ final int actions = AccessibilityAction.sStandardActions.size();
+ for (int i = 0; i < actions; i++) {
+ AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i);
+ if (flag == currentAction.mSerializationFlag) {
+ return currentAction;
+ }
+ }
+
+ return null;
+ }
+
+ private void addStandardActions(int serializationIdMask) {
+ int remainingIds = serializationIdMask;
while (remainingIds > 0) {
final int id = 1 << Integer.numberOfTrailingZeros(remainingIds);
remainingIds &= ~id;
- AccessibilityAction action = getActionSingleton(id);
+ AccessibilityAction action = getActionSingletonBySerializationFlag(id);
addAction(action);
}
}
@@ -3750,61 +3762,56 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public static final class AccessibilityAction {
+ /** @hide */
+ public static final ArraySet sStandardActions = new ArraySet<>();
+
/**
* Action that gives input focus to the node.
*/
public static final AccessibilityAction ACTION_FOCUS =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_FOCUS, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_FOCUS);
/**
* Action that clears input focus of the node.
*/
public static final AccessibilityAction ACTION_CLEAR_FOCUS =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_FOCUS, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS);
/**
* Action that selects the node.
*/
public static final AccessibilityAction ACTION_SELECT =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_SELECT, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_SELECT);
/**
* Action that deselects the node.
*/
public static final AccessibilityAction ACTION_CLEAR_SELECTION =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_SELECTION, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
/**
* Action that clicks on the node info.
*/
public static final AccessibilityAction ACTION_CLICK =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLICK, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK);
/**
* Action that long clicks on the node.
*/
public static final AccessibilityAction ACTION_LONG_CLICK =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_LONG_CLICK, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
/**
* Action that gives accessibility focus to the node.
*/
public static final AccessibilityAction ACTION_ACCESSIBILITY_FOCUS =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
/**
* Action that clears accessibility focus of the node.
*/
public static final AccessibilityAction ACTION_CLEAR_ACCESSIBILITY_FOCUS =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
/**
* Action that requests to go to the next entity in this node's text
@@ -3850,8 +3857,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE
*/
public static final AccessibilityAction ACTION_NEXT_AT_MOVEMENT_GRANULARITY =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
/**
* Action that requests to go to the previous entity in this node's text
@@ -3898,7 +3904,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*/
public static final AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY =
new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, null);
+ AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
/**
* Action to move to the next HTML element of a given type. For example, move
@@ -3916,8 +3922,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*
*/
public static final AccessibilityAction ACTION_NEXT_HTML_ELEMENT =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_NEXT_HTML_ELEMENT);
/**
* Action to move to the previous HTML element of a given type. For example, move
@@ -3935,43 +3940,37 @@ public class AccessibilityNodeInfo implements Parcelable {
*
*/
public static final AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_PREVIOUS_HTML_ELEMENT);
/**
* Action to scroll the node content forward.
*/
public static final AccessibilityAction ACTION_SCROLL_FORWARD =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_SCROLL_FORWARD, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
/**
* Action to scroll the node content backward.
*/
public static final AccessibilityAction ACTION_SCROLL_BACKWARD =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
/**
* Action to copy the current selection to the clipboard.
*/
public static final AccessibilityAction ACTION_COPY =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_COPY, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_COPY);
/**
* Action to paste the current clipboard content.
*/
public static final AccessibilityAction ACTION_PASTE =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_PASTE, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_PASTE);
/**
* Action to cut the current selection and place it to the clipboard.
*/
public static final AccessibilityAction ACTION_CUT =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_CUT, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_CUT);
/**
* Action to set the selection. Performing this action with no arguments
@@ -3997,29 +3996,25 @@ public class AccessibilityNodeInfo implements Parcelable {
* AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT
*/
public static final AccessibilityAction ACTION_SET_SELECTION =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_SET_SELECTION, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
/**
* Action to expand an expandable node.
*/
public static final AccessibilityAction ACTION_EXPAND =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_EXPAND, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_EXPAND);
/**
* Action to collapse an expandable node.
*/
public static final AccessibilityAction ACTION_COLLAPSE =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_COLLAPSE, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
/**
* Action to dismiss a dismissable node.
*/
public static final AccessibilityAction ACTION_DISMISS =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_DISMISS, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_DISMISS);
/**
* Action that sets the text of the node. Performing the action without argument,
@@ -4038,8 +4033,7 @@ public class AccessibilityNodeInfo implements Parcelable {
*
*/
public static final AccessibilityAction ACTION_SET_TEXT =
- new AccessibilityAction(
- AccessibilityNodeInfo.ACTION_SET_TEXT, null);
+ new AccessibilityAction(AccessibilityNodeInfo.ACTION_SET_TEXT);
/**
* Action that requests the node make its bounding rectangle visible
@@ -4048,7 +4042,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* @see View#requestRectangleOnScreen(Rect)
*/
public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
- new AccessibilityAction(R.id.accessibilityActionShowOnScreen, null);
+ new AccessibilityAction(R.id.accessibilityActionShowOnScreen);
/**
* Action that scrolls the node to make the specified collection
@@ -4063,37 +4057,37 @@ public class AccessibilityNodeInfo implements Parcelable {
* @see AccessibilityNodeInfo#getCollectionInfo()
*/
public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
- new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
+ new AccessibilityAction(R.id.accessibilityActionScrollToPosition);
/**
* Action to scroll the node content up.
*/
public static final AccessibilityAction ACTION_SCROLL_UP =
- new AccessibilityAction(R.id.accessibilityActionScrollUp, null);
+ new AccessibilityAction(R.id.accessibilityActionScrollUp);
/**
* Action to scroll the node content left.
*/
public static final AccessibilityAction ACTION_SCROLL_LEFT =
- new AccessibilityAction(R.id.accessibilityActionScrollLeft, null);
+ new AccessibilityAction(R.id.accessibilityActionScrollLeft);
/**
* Action to scroll the node content down.
*/
public static final AccessibilityAction ACTION_SCROLL_DOWN =
- new AccessibilityAction(R.id.accessibilityActionScrollDown, null);
+ new AccessibilityAction(R.id.accessibilityActionScrollDown);
/**
* Action to scroll the node content right.
*/
public static final AccessibilityAction ACTION_SCROLL_RIGHT =
- new AccessibilityAction(R.id.accessibilityActionScrollRight, null);
+ new AccessibilityAction(R.id.accessibilityActionScrollRight);
/**
* Action that context clicks the node.
*/
public static final AccessibilityAction ACTION_CONTEXT_CLICK =
- new AccessibilityAction(R.id.accessibilityActionContextClick, null);
+ new AccessibilityAction(R.id.accessibilityActionContextClick);
/**
* Action that sets progress between {@link RangeInfo#getMin() RangeInfo.getMin()} and
@@ -4106,7 +4100,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* @see RangeInfo
*/
public static final AccessibilityAction ACTION_SET_PROGRESS =
- new AccessibilityAction(R.id.accessibilityActionSetProgress, null);
+ new AccessibilityAction(R.id.accessibilityActionSetProgress);
/**
* Action to move a window to a new location.
@@ -4116,45 +4110,14 @@ public class AccessibilityNodeInfo implements Parcelable {
* {@link AccessibilityNodeInfo#ACTION_ARGUMENT_MOVE_WINDOW_Y}
*/
public static final AccessibilityAction ACTION_MOVE_WINDOW =
- new AccessibilityAction(R.id.accessibilityActionMoveWindow, null);
-
- private static final ArraySet sStandardActions = new ArraySet<>();
- static {
- sStandardActions.add(ACTION_FOCUS);
- sStandardActions.add(ACTION_CLEAR_FOCUS);
- sStandardActions.add(ACTION_SELECT);
- sStandardActions.add(ACTION_CLEAR_SELECTION);
- sStandardActions.add(ACTION_CLICK);
- sStandardActions.add(ACTION_LONG_CLICK);
- sStandardActions.add(ACTION_ACCESSIBILITY_FOCUS);
- sStandardActions.add(ACTION_CLEAR_ACCESSIBILITY_FOCUS);
- sStandardActions.add(ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
- sStandardActions.add(ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
- sStandardActions.add(ACTION_NEXT_HTML_ELEMENT);
- sStandardActions.add(ACTION_PREVIOUS_HTML_ELEMENT);
- sStandardActions.add(ACTION_SCROLL_FORWARD);
- sStandardActions.add(ACTION_SCROLL_BACKWARD);
- sStandardActions.add(ACTION_COPY);
- sStandardActions.add(ACTION_PASTE);
- sStandardActions.add(ACTION_CUT);
- sStandardActions.add(ACTION_SET_SELECTION);
- sStandardActions.add(ACTION_EXPAND);
- sStandardActions.add(ACTION_COLLAPSE);
- sStandardActions.add(ACTION_DISMISS);
- sStandardActions.add(ACTION_SET_TEXT);
- sStandardActions.add(ACTION_SHOW_ON_SCREEN);
- sStandardActions.add(ACTION_SCROLL_TO_POSITION);
- sStandardActions.add(ACTION_SCROLL_UP);
- sStandardActions.add(ACTION_SCROLL_LEFT);
- sStandardActions.add(ACTION_SCROLL_DOWN);
- sStandardActions.add(ACTION_SCROLL_RIGHT);
- sStandardActions.add(ACTION_SET_PROGRESS);
- sStandardActions.add(ACTION_CONTEXT_CLICK);
- }
+ new AccessibilityAction(R.id.accessibilityActionMoveWindow);
private final int mActionId;
private final CharSequence mLabel;
+ /** @hide */
+ public int mSerializationFlag = -1;
+
/**
* Creates a new AccessibilityAction. For adding a standard action without a specific label,
* use the static constants.
@@ -4181,6 +4144,16 @@ public class AccessibilityNodeInfo implements Parcelable {
mLabel = label;
}
+ /**
+ * Constructor for a {@link #sStandardActions standard} action
+ */
+ private AccessibilityAction(int standardActionId) {
+ this(standardActionId, null);
+
+ mSerializationFlag = (int) bitAt(sStandardActions.size());
+ sStandardActions.add(this);
+ }
+
/**
* Gets the id for this action.
*
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 96b443d28abc7..4b50b35878258 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.ArrayUtils.isEmpty;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.util.ArraySet;
import java.util.ArrayList;
import java.util.Collection;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityNodeInfoTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityNodeInfoTest.java
new file mode 100644
index 0000000000000..7f979738ee528
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityNodeInfoTest.java
@@ -0,0 +1,63 @@
+package com.android.server.accessibility;
+
+import static org.junit.Assert.fail;
+
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArraySet;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+
+import com.android.internal.util.CollectionUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodeInfoTest {
+
+ @Test
+ public void testStandardActions_serializationFlagIsValid() {
+ AccessibilityAction brokenStandardAction = CollectionUtils.find(
+ new ArrayList<>(AccessibilityAction.sStandardActions),
+ action -> Integer.bitCount(action.mSerializationFlag) != 1);
+ if (brokenStandardAction != null) {
+ String message = "Invalid serialization flag(0x"
+ + Integer.toHexString(brokenStandardAction.mSerializationFlag)
+ + ") in " + brokenStandardAction;
+ if (brokenStandardAction.mSerializationFlag == 0L) {
+ message += "\nThis is likely due to an overflow";
+ }
+ fail(message);
+ }
+
+ brokenStandardAction = CollectionUtils.find(
+ new ArrayList<>(AccessibilityAction.sStandardActions),
+ action -> Integer.bitCount(action.getId()) == 1
+ && action.getId() <= AccessibilityNodeInfo.LAST_LEGACY_STANDARD_ACTION
+ && action.getId() != action.mSerializationFlag);
+ if (brokenStandardAction != null) {
+ fail("Serialization flag(0x"
+ + Integer.toHexString(brokenStandardAction.mSerializationFlag)
+ + ") is different from legacy action id(0x"
+ + Integer.toHexString(brokenStandardAction.getId())
+ + ") in " + brokenStandardAction);
+ }
+ }
+
+ @Test
+ public void testStandardActions_idsAreUnique() {
+ ArraySet actions = AccessibilityAction.sStandardActions;
+ for (int i = 0; i < actions.size(); i++) {
+ for (int j = 0; j < i; j++) {
+ int id = actions.valueAt(i).getId();
+ if (id == actions.valueAt(j).getId()) {
+ fail("Id 0x" + Integer.toHexString(id)
+ + " is duplicated for standard actions #" + i + " and #" + j);
+ }
+ }
+ }
+ }
+
+}