diff --git a/api/current.txt b/api/current.txt index 8df9c24010fc3..ab91974fb3b6f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -26352,21 +26352,28 @@ package android.view.accessibility { method public void setVisibleToUser(boolean); method public void writeToParcel(android.os.Parcel, int); field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40 + field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN"; field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; + field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT"; + field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT"; field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80 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_COPY = 16384; // 0x4000 + field public static final int ACTION_CUT = 65536; // 0x10000 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 field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400 + field public static final int ACTION_PASTE = 32768; // 0x8000 field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200 field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800 field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000 field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000 field public static final int ACTION_SELECT = 4; // 0x4 + field public static final int ACTION_SET_SELECTION = 131072; // 0x20000 field public static final android.os.Parcelable.Creator CREATOR; field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2 field public static final int FOCUS_INPUT = 1; // 0x1 diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b9babdcc2e039..11c80c26ebf19 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -1562,9 +1562,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ int mAccessibilityViewId = NO_ID; - /** - * @hide - */ private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; /** @@ -2516,8 +2513,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * The undefined cursor position. + * + * @hide */ - private static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; + public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; /** * Indicates that the screen has changed state and is now off. @@ -7009,21 +7008,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (arguments != null) { final int granularity = arguments.getInt( AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); - return nextAtGranularity(granularity); + final boolean extendSelection = arguments.getBoolean( + AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); + return nextAtGranularity(granularity, extendSelection); } } break; case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { if (arguments != null) { final int granularity = arguments.getInt( AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); - return previousAtGranularity(granularity); + final boolean extendSelection = arguments.getBoolean( + AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); + return previousAtGranularity(granularity, extendSelection); } } break; } return false; } - private boolean nextAtGranularity(int granularity) { + private boolean nextAtGranularity(int granularity, boolean extendSelection) { CharSequence text = getIterableTextForAccessibility(); if (text == null || text.length() == 0) { return false; @@ -7032,21 +7035,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (iterator == null) { return false; } - final int current = getAccessibilityCursorPosition(); + int current = getAccessibilitySelectionEnd(); + if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { + current = 0; + } final int[] range = iterator.following(current); if (range == null) { return false; } final int start = range[0]; final int end = range[1]; - setAccessibilityCursorPosition(end); + if (extendSelection && isAccessibilitySelectionExtendable()) { + int selectionStart = getAccessibilitySelectionStart(); + if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { + selectionStart = start; + } + setAccessibilitySelection(selectionStart, end); + } else { + setAccessibilitySelection(end, end); + } sendViewTextTraversedAtGranularityEvent( AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, granularity, start, end); return true; } - private boolean previousAtGranularity(int granularity) { + private boolean previousAtGranularity(int granularity, boolean extendSelection) { CharSequence text = getIterableTextForAccessibility(); if (text == null || text.length() == 0) { return false; @@ -7055,15 +7069,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (iterator == null) { return false; } - int current = getAccessibilityCursorPosition(); + int current = getAccessibilitySelectionStart(); if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { current = text.length(); - setAccessibilityCursorPosition(current); - } else if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) { - // When traversing by character we always put the cursor after the character - // to ease edit and have to compensate before asking the for previous segment. - current--; - setAccessibilityCursorPosition(current); } final int[] range = iterator.preceding(current); if (range == null) { @@ -7071,11 +7079,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } final int start = range[0]; final int end = range[1]; - // Always put the cursor after the character to ease edit. - if (granularity == AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER) { - setAccessibilityCursorPosition(end); + if (extendSelection && isAccessibilitySelectionExtendable()) { + int selectionEnd = getAccessibilitySelectionEnd(); + if (selectionEnd == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { + selectionEnd = end; + } + setAccessibilitySelection(start, selectionEnd); } else { - setAccessibilityCursorPosition(start); + setAccessibilitySelection(start, start); } sendViewTextTraversedAtGranularityEvent( AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY, @@ -7095,17 +7106,39 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Gets whether accessibility selection can be extended. + * + * @return If selection is extensible. + * * @hide */ - public int getAccessibilityCursorPosition() { + public boolean isAccessibilitySelectionExtendable() { + return false; + } + + /** + * @hide + */ + public int getAccessibilitySelectionStart() { return mAccessibilityCursorPosition; } /** * @hide */ - public void setAccessibilityCursorPosition(int position) { - mAccessibilityCursorPosition = position; + public int getAccessibilitySelectionEnd() { + return getAccessibilitySelectionStart(); + } + + /** + * @hide + */ + public void setAccessibilitySelection(int start, int end) { + if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { + mAccessibilityCursorPosition = start; + } else { + mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; + } } private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 6d0a2375ece6c..7a3d7c3c14c7b 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -131,16 +131,22 @@ public class AccessibilityNodeInfo implements Parcelable { * at a given movement granularity. For example, move to the next character, * word, etc. *
- * Arguments: {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}
* Bundle arguments = new Bundle();
* arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
* AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+ * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
+ * false);
* info.performAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY, arguments);
*
- * Example:
+ * Arguments: {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
+ * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}
+ * Example: Move to the previous character and do not extend selection.
*
- * Arguments: {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}
* Bundle arguments = new Bundle();
* arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
* AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER);
+ * arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
+ * false);
* info.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
* arguments);
*
- * Example:
+ * Arguments: {@link #ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT}<,
+ * {@link #ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN}
+ * Example: Move to the next character and do not extend selection.
*
+ * Arguments: {@link #ACTION_ARGUMENT_SELECTION_START_INT},
+ * {@link #ACTION_ARGUMENT_SELECTION_END_INT}
+ * Bundle arguments = new Bundle();
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 1);
+ * arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, 2);
+ * info.performAction(AccessibilityNodeInfo.ACTION_SET_SELECTION, arguments);
+ *
+ * Example:
+ *
@@ -226,9 +273,12 @@ public class AccessibilityNodeInfo implements Parcelable { * Actions: {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY}, * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY} *
+ * + * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY + * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY */ public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = - "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; + "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT"; /** * Argument for which HTML element to get moving to the next/previous HTML element. @@ -237,9 +287,51 @@ public class AccessibilityNodeInfo implements Parcelable { * Actions: {@link #ACTION_NEXT_HTML_ELEMENT}, * {@link #ACTION_PREVIOUS_HTML_ELEMENT} * + * + * @see #ACTION_NEXT_HTML_ELEMENT + * @see #ACTION_PREVIOUS_HTML_ELEMENT */ public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = - "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; + "ACTION_ARGUMENT_HTML_ELEMENT_STRING"; + + /** + * Argument for whether when moving at granularity to extend the selection + * or to move it otherwise. + *
+ * Type: boolean
+ * Actions: {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
+ * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
+ *
+ * Type: int
+ * Actions: {@link #ACTION_SET_SELECTION}
+ *
+ * Type: int
+ * Actions: {@link #ACTION_SET_SELECTION}
+ *