Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit abad55d8 authored by Svetoslav's avatar Svetoslav
Browse files

Fixing the accessibility text traversal in extend mode.

We added APIs to allow an accessibility service to extend the
selection while moving the cursor at a given granularity such
as word, character, etc. The problem is that the traversal was
extending only the end of the selection while moving forward
and the start of the selection while moving backward. This leads
to a case in which the user cannot shrink/extend the selection
because for example instead of shrinking the end of the selection
the implementation was extending the start.

Now extending the selection moves only the selection end. This is
the same behavior as text view using a keyboard.

Tests: https://googleplex-android-review.googlesource.com/#/c/307062

bug:8839844

Change-Id: Id6965b102647df909f61301fcc8ec05458dd5881
parent a6303d8a
Loading
Loading
Loading
Loading
+18 −48
Original line number Original line Diff line number Diff line
@@ -7069,7 +7069,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                            AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
                            AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
                    final boolean extendSelection = arguments.getBoolean(
                    final boolean extendSelection = arguments.getBoolean(
                            AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
                            AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
                    return nextAtGranularity(granularity, extendSelection);
                    return traverseAtGranularity(granularity, true, extendSelection);
                }
                }
            } break;
            } break;
            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: {
            case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: {
@@ -7078,7 +7078,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                            AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
                            AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT);
                    final boolean extendSelection = arguments.getBoolean(
                    final boolean extendSelection = arguments.getBoolean(
                            AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
                            AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN);
                    return previousAtGranularity(granularity, extendSelection);
                    return traverseAtGranularity(granularity, false, extendSelection);
                }
                }
            } break;
            } break;
            case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
            case AccessibilityNodeInfo.ACTION_SET_SELECTION: {
@@ -7103,7 +7103,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return false;
        return false;
    }
    }
    private boolean nextAtGranularity(int granularity, boolean extendSelection) {
    private boolean traverseAtGranularity(int granularity, boolean forward,
            boolean extendSelection) {
        CharSequence text = getIterableTextForAccessibility();
        CharSequence text = getIterableTextForAccessibility();
        if (text == null || text.length() == 0) {
        if (text == null || text.length() == 0) {
            return false;
            return false;
@@ -7114,60 +7115,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        }
        int current = getAccessibilitySelectionEnd();
        int current = getAccessibilitySelectionEnd();
        if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
        if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
            current = 0;
            current = forward ? 0 : text.length();
        }
        }
        final int[] range = iterator.following(current);
        final int[] range = forward ? iterator.following(current) : iterator.preceding(current);
        if (range == null) {
        if (range == null) {
            return false;
            return false;
        }
        }
        final int start = range[0];
        final int segmentStart = range[0];
        final int end = range[1];
        final int segmentEnd = range[1];
        int selectionStart;
        int selectionEnd;
        if (extendSelection && isAccessibilitySelectionExtendable()) {
        if (extendSelection && isAccessibilitySelectionExtendable()) {
            int selectionStart = getAccessibilitySelectionStart();
            selectionStart = getAccessibilitySelectionStart();
            if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
            if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
                selectionStart = start;
                selectionStart = forward ? segmentStart : segmentEnd;
            }
            }
            setAccessibilitySelection(selectionStart, end);
            selectionEnd = forward ? segmentEnd : segmentStart;
        } else {
        } else {
            setAccessibilitySelection(end, end);
            selectionStart = selectionEnd= forward ? segmentEnd : segmentStart;
        }
        }
        sendViewTextTraversedAtGranularityEvent(
        setAccessibilitySelection(selectionStart, selectionEnd);
                AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY,
        final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY
                granularity, start, end);
                : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
        return true;
        sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd);
    }
    private boolean previousAtGranularity(int granularity, boolean extendSelection) {
        CharSequence text = getIterableTextForAccessibility();
        if (text == null || text.length() == 0) {
            return false;
        }
        TextSegmentIterator iterator = getIteratorForGranularity(granularity);
        if (iterator == null) {
            return false;
        }
        int current = getAccessibilitySelectionStart();
        if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
            current = text.length();
        }
        final int[] range = iterator.preceding(current);
        if (range == null) {
            return false;
        }
        final int start = range[0];
        final int end = range[1];
        if (extendSelection && isAccessibilitySelectionExtendable()) {
            int selectionEnd = getAccessibilitySelectionEnd();
            if (selectionEnd == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) {
                selectionEnd = end;
            }
            setAccessibilitySelection(start, selectionEnd);
        } else {
            setAccessibilitySelection(start, start);
        }
        sendViewTextTraversedAtGranularityEvent(
                AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
                granularity, start, end);
        return true;
        return true;
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -1248,7 +1248,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
                    if (eventTypeCount > 0) {
                    if (eventTypeCount > 0) {
                        builder.append(", ");
                        builder.append(", ");
                    }
                    }
                    builder.append("TYPE_CURRENT_AT_GRANULARITY_MOVEMENT_CHANGED");
                    builder.append("TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY");
                    eventTypeCount++;
                    eventTypeCount++;
                } break;
                } break;
                case TYPE_GESTURE_DETECTION_START: {
                case TYPE_GESTURE_DETECTION_START: {
+7 −1
Original line number Original line Diff line number Diff line
@@ -8722,8 +8722,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                && getAccessibilitySelectionEnd() == end) {
                && getAccessibilitySelectionEnd() == end) {
            return;
            return;
        }
        }
        // Hide all selection controllers used for adjusting selection
        // since we are doing so explicitlty by other means and these
        // controllers interact with how selection behaves.
        if (mEditor != null) {
            mEditor.hideControllers();
        }
        CharSequence text = getIterableTextForAccessibility();
        CharSequence text = getIterableTextForAccessibility();
        if (start >= 0 && start <= end && end <= text.length()) {
        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
            Selection.setSelection((Spannable) text, start, end);
            Selection.setSelection((Spannable) text, start, end);
        } else {
        } else {
            Selection.removeSelection((Spannable) text);
            Selection.removeSelection((Spannable) text);