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

Commit 1ce03340 authored by Justin Ghan's avatar Justin Ghan
Browse files

TextView implementation of select range and delete range gestures

Bug: 247570808
Test: atest android.widget.cts.TextViewHandwritingGestureTest
Change-Id: I2cfd579c1dd213fa1847f302b56d22bda0c96f19
parent f3d63567
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -595,6 +595,10 @@ public class EditorInfo implements InputType, Parcelable {
                == HandwritingGesture.GESTURE_TYPE_SELECT) {
            list.add(SelectGesture.class);
        }
        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_SELECT_RANGE)
                == HandwritingGesture.GESTURE_TYPE_SELECT_RANGE) {
            list.add(SelectRangeGesture.class);
        }
        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_INSERT)
                == HandwritingGesture.GESTURE_TYPE_INSERT) {
            list.add(InsertGesture.class);
@@ -603,6 +607,10 @@ public class EditorInfo implements InputType, Parcelable {
                == HandwritingGesture.GESTURE_TYPE_DELETE) {
            list.add(DeleteGesture.class);
        }
        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_DELETE_RANGE)
                == HandwritingGesture.GESTURE_TYPE_DELETE_RANGE) {
            list.add(DeleteRangeGesture.class);
        }
        if ((mSupportedHandwritingGestureTypes & HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE)
                == HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE) {
            list.add(RemoveSpaceGesture.class);
+114 −51
Original line number Diff line number Diff line
@@ -189,6 +189,7 @@ import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
import android.view.inputmethod.DeleteGesture;
import android.view.inputmethod.DeleteRangeGesture;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -199,6 +200,7 @@ import android.view.inputmethod.InsertGesture;
import android.view.inputmethod.JoinOrSplitGesture;
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
import android.view.inspector.InspectableProperty;
import android.view.inspector.InspectableProperty.EnumEntry;
import android.view.inspector.InspectableProperty.FlagEntry;
@@ -9096,7 +9098,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                ArrayList<Class<? extends HandwritingGesture>> gestures = new ArrayList<>();
                gestures.add(SelectGesture.class);
                gestures.add(SelectRangeGesture.class);
                gestures.add(DeleteGesture.class);
                gestures.add(DeleteRangeGesture.class);
                gestures.add(InsertGesture.class);
                gestures.add(RemoveSpaceGesture.class);
                gestures.add(JoinOrSplitGesture.class);
@@ -9324,6 +9328,26 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    /** @hide */
    public int performHandwritingSelectRangeGesture(@NonNull SelectRangeGesture gesture) {
        Range<Integer> startRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getSelectionStartArea()),
                gesture.getGranularity());
        if (startRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> endRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getSelectionEndArea()),
                gesture.getGranularity());
        if (endRange == null || endRange.getUpper() <= startRange.getLower()) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> range = startRange.extend(endRange);
        Selection.setSelection(getEditableText(), range.getLower(), range.getUpper());
        mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    /** @hide */
    public int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture) {
        Range<Integer> range = getRangeForRect(
@@ -9332,20 +9356,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        if (range == null) {
            return handleGestureFailure(gesture);
        }
        if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
            range = adjustHandwritingDeleteGestureRange(range);
        }
        getEditableText().delete(range.getLower(), range.getUpper());
        Selection.setSelection(getEditableText(), range.getLower());
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    /** @hide */
    public int performHandwritingDeleteRangeGesture(@NonNull DeleteRangeGesture gesture) {
        Range<Integer> startRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getDeletionStartArea()),
                gesture.getGranularity());
        if (startRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> endRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getDeletionEndArea()),
                gesture.getGranularity());
        if (endRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> range = startRange.extend(endRange);
        if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
            range = adjustHandwritingDeleteGestureRange(range);
        }
        getEditableText().delete(range.getLower(), range.getUpper());
        Selection.setSelection(getEditableText(), range.getLower());
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    private Range<Integer> adjustHandwritingDeleteGestureRange(Range<Integer> range) {
        // For handwriting delete gestures with word granularity, adjust the start and end offsets
        // to remove extra whitespace around the deleted text.
        int start = range.getLower();
        int end = range.getUpper();
        // For word granularity, adjust the start and end offsets to remove extra whitespace around
        // the deleted text.
        if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
        // If the deleted text is at the start of the text, the behavior is the same as the case
        // where the deleted text follows a new line character.
        int codePointBeforeStart = start > 0
                ? Character.codePointBefore(mText, start) : TextUtils.LINE_FEED_CODE_POINT;
            // If the deleted text is at the end of the text, the behavior is the same as the case
            // where the deleted text precedes a new line character.
        // If the deleted text is at the end of the text, the behavior is the same as the case where
        // the deleted text precedes a new line character.
        int codePointAtEnd = end < mText.length()
                ? Character.codePointAt(mText, end) : TextUtils.LINE_FEED_CODE_POINT;
        if (TextUtils.isWhitespaceExceptNewline(codePointBeforeStart)
                && (TextUtils.isWhitespace(codePointAtEnd)
                        || TextUtils.isPunctuation(codePointAtEnd))) {
@@ -9364,7 +9425,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                if (start == 0) break;
                codePointBeforeStart = Character.codePointBefore(mText, start);
            } while (TextUtils.isWhitespaceExceptNewline(codePointBeforeStart));
            } else if (TextUtils.isWhitespaceExceptNewline(codePointAtEnd)
            return new Range(start, end);
        }
        if (TextUtils.isWhitespaceExceptNewline(codePointAtEnd)
                && (TextUtils.isWhitespace(codePointBeforeStart)
                        || TextUtils.isPunctuation(codePointBeforeStart))) {
            // Remove whitespace (except new lines) after the deleted text, in these cases:
@@ -9380,12 +9444,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                if (end == mText.length()) break;
                codePointAtEnd = Character.codePointAt(mText, end);
            } while (TextUtils.isWhitespaceExceptNewline(codePointAtEnd));
            }
            return new Range(start, end);
        }
        getEditableText().delete(start, end);
        Selection.setSelection(getEditableText(), start);
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
        // Return the original range.
        return range;
    }
    /** @hide */
+6 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.DeleteGesture;
import android.view.inputmethod.DeleteRangeGesture;
import android.view.inputmethod.DumpableInputConnection;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -44,6 +45,7 @@ import android.view.inputmethod.InsertGesture;
import android.view.inputmethod.JoinOrSplitGesture;
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
import android.widget.TextView;

import java.util.concurrent.Executor;
@@ -275,8 +277,12 @@ public final class EditableInputConnection extends BaseInputConnection
        int result;
        if (gesture instanceof SelectGesture) {
            result = mTextView.performHandwritingSelectGesture((SelectGesture) gesture);
        } else if (gesture instanceof SelectRangeGesture) {
            result = mTextView.performHandwritingSelectRangeGesture((SelectRangeGesture) gesture);
        } else if (gesture instanceof DeleteGesture) {
            result = mTextView.performHandwritingDeleteGesture((DeleteGesture) gesture);
        } else if (gesture instanceof DeleteRangeGesture) {
            result = mTextView.performHandwritingDeleteRangeGesture((DeleteRangeGesture) gesture);
        } else if (gesture instanceof InsertGesture) {
            result = mTextView.performHandwritingInsertGesture((InsertGesture) gesture);
        } else if (gesture instanceof RemoveSpaceGesture) {