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

Commit 9d0b39c2 authored by Justin Ghan's avatar Justin Ghan
Browse files

Update Layout#getRangeForRect to not use Range

android.util.Range is not suitable for text ranges since it uses
inclusive boundaries, whereas the convention in text is to represent
ranges with an inclusive start boundary and exclusive end boundary. So
the API is updated to use an array of two ints to represent the text
range.

Bug: 251085162
Test: atest android.text.cts.LayoutGetRangeForRectTest
Change-Id: I54ab6d2741d1cfbbb743e477de4fa7299382fcfb
parent 316f451f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -45401,7 +45401,7 @@ package android.text {
    method public final int getParagraphLeft(int);
    method public final int getParagraphRight(int);
    method public float getPrimaryHorizontal(int);
    method @Nullable public android.util.Range<java.lang.Integer> getRangeForRect(@NonNull android.graphics.RectF, @NonNull android.text.SegmentFinder, @NonNull android.text.Layout.TextInclusionStrategy);
    method @Nullable public int[] getRangeForRect(@NonNull android.graphics.RectF, @NonNull android.text.SegmentFinder, @NonNull android.text.Layout.TextInclusionStrategy);
    method public float getSecondaryHorizontal(int);
    method public void getSelectionPath(int, int, android.graphics.Path);
    method public final float getSpacingAdd();
+5 −7
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.text.style.LineBackgroundSpan;
import android.text.style.ParagraphStyle;
import android.text.style.ReplacementSpan;
import android.text.style.TabStopSpan;
import android.util.Range;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -1860,12 +1859,11 @@ public abstract class Layout {
     *     text segment
     * @param inclusionStrategy strategy for determining whether a text segment is inside the
     *     specified area
     * @return an integer range where the endpoints are the start (inclusive) and end (exclusive)
     *     character offsets of the text range, or null if there are no text segments inside the
     *     area
     * @return int array of size 2 containing the start (inclusive) and end (exclusive) character
     *     offsets of the text range, or null if there are no text segments inside the area
     */
    @Nullable
    public Range<Integer> getRangeForRect(@NonNull RectF area, @NonNull SegmentFinder segmentFinder,
    public int[] getRangeForRect(@NonNull RectF area, @NonNull SegmentFinder segmentFinder,
            @NonNull TextInclusionStrategy inclusionStrategy) {
        // Find the first line whose bottom (without line spacing) is below the top of the area.
        int startLine = getLineForVertical((int) area.top);
@@ -1923,7 +1921,7 @@ public abstract class Layout {
        start = segmentFinder.previousStartBoundary(start + 1);
        end = segmentFinder.nextEndBoundary(end - 1);

        return new Range(start, end);
        return new int[] {start, end};
    }

    /**
+28 −25
Original line number Diff line number Diff line
@@ -151,7 +151,6 @@ import android.util.DisplayMetrics;
import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Range;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -9317,40 +9316,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    /** @hide */
    public int performHandwritingSelectGesture(@NonNull SelectGesture gesture) {
        Range<Integer> range = getRangeForRect(
        int[] range = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getSelectionArea()),
                gesture.getGranularity());
        if (range == null) {
            return handleGestureFailure(gesture);
        }
        Selection.setSelection(getEditableText(), range.getLower(), range.getUpper());
        Selection.setSelection(getEditableText(), range[0], range[1]);
        mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    /** @hide */
    public int performHandwritingSelectRangeGesture(@NonNull SelectRangeGesture gesture) {
        Range<Integer> startRange = getRangeForRect(
        int[] startRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getSelectionStartArea()),
                gesture.getGranularity());
        if (startRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> endRange = getRangeForRect(
        int[] endRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getSelectionEndArea()),
                gesture.getGranularity());
        if (endRange == null || endRange.getUpper() <= startRange.getLower()) {
        if (endRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> range = startRange.extend(endRange);
        Selection.setSelection(getEditableText(), range.getLower(), range.getUpper());
        int[] range = new int[] {
                Math.min(startRange[0], endRange[0]), Math.max(startRange[1], endRange[1])
        };
        Selection.setSelection(getEditableText(), range[0], range[1]);
        mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    /** @hide */
    public int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture) {
        Range<Integer> range = getRangeForRect(
        int[] range = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getDeletionArea()),
                gesture.getGranularity());
        if (range == null) {
@@ -9361,42 +9362,44 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            range = adjustHandwritingDeleteGestureRange(range);
        }
        getEditableText().delete(range.getLower(), range.getUpper());
        Selection.setSelection(getEditableText(), range.getLower());
        getEditableText().delete(range[0], range[1]);
        Selection.setSelection(getEditableText(), range[0]);
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    /** @hide */
    public int performHandwritingDeleteRangeGesture(@NonNull DeleteRangeGesture gesture) {
        Range<Integer> startRange = getRangeForRect(
        int[] startRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getDeletionStartArea()),
                gesture.getGranularity());
        if (startRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> endRange = getRangeForRect(
        int[] endRange = getRangeForRect(
                convertFromScreenToContentCoordinates(gesture.getDeletionEndArea()),
                gesture.getGranularity());
        if (endRange == null) {
            return handleGestureFailure(gesture);
        }
        Range<Integer> range = startRange.extend(endRange);
        int[] range = new int[] {
                Math.min(startRange[0], endRange[0]), Math.max(startRange[1], endRange[1])
        };
        if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
            range = adjustHandwritingDeleteGestureRange(range);
        }
        getEditableText().delete(range.getLower(), range.getUpper());
        Selection.setSelection(getEditableText(), range.getLower());
        getEditableText().delete(range[0], range[1]);
        Selection.setSelection(getEditableText(), range[0]);
        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
    }
    private Range<Integer> adjustHandwritingDeleteGestureRange(Range<Integer> range) {
    private int[] adjustHandwritingDeleteGestureRange(int[] 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();
        int start = range[0];
        int end = range[1];
        // 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.
@@ -9425,7 +9428,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                if (start == 0) break;
                codePointBeforeStart = Character.codePointBefore(mText, start);
            } while (TextUtils.isWhitespaceExceptNewline(codePointBeforeStart));
            return new Range(start, end);
            return new int[] {start, end};
        }
        if (TextUtils.isWhitespaceExceptNewline(codePointAtEnd)
@@ -9444,7 +9447,7 @@ 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);
            return new int[] {start, end};
        }
        // Return the original range.
@@ -9494,14 +9497,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                lineVerticalCenter + 0.1f,
                Math.max(startPoint.x, endPoint.x),
                lineVerticalCenter - 0.1f);
        Range<Integer> range = mLayout.getRangeForRect(
        int[] range = mLayout.getRangeForRect(
                area, new GraphemeClusterSegmentFinder(mText, mTextPaint),
                Layout.INCLUSION_STRATEGY_ANY_OVERLAP);
        if (range == null) {
            return handleGestureFailure(gesture);
        }
        int startOffset = range.getLower();
        int endOffset = range.getUpper();
        int startOffset = range[0];
        int endOffset = range[1];
        // TODO(b/247557062): This doesn't handle bidirectional text correctly.
        Pattern whitespacePattern = getWhitespacePattern();
@@ -9606,7 +9609,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    }
    @Nullable
    private Range<Integer> getRangeForRect(@NonNull RectF area, int granularity) {
    private int[] getRangeForRect(@NonNull RectF area, int granularity) {
        SegmentFinder segmentFinder;
        if (granularity == HandwritingGesture.GRANULARITY_WORD) {
            WordIterator wordIterator = getWordIterator();