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

Commit fb748b35 authored by Petar Šegina's avatar Petar Šegina
Browse files

Add getSelection(..., RectangleConsumer) to Layout

In order to generate the Smart Select animation, we need a list of
rectangles which represent a given selection. The current
getSelectionPath code can only fill out a Path, which loses the
rectangle information in the process.

Instead of working directly with a Path, a RectangleConsumer is
introduced, which is an abstraction over an element that can accept
rectangles (for example, a Path or a List<Rect>).

getSelectionPath is now implemented with this new method using a simple
consumer which takes the rectangles and feeds them to the path.

Test: cts-tradefed run cts-dev -m CtsWidgetTestCases -d -t android.widget.cts.TextViewTest#testGetFocusedRect
Test: manual - verify text selection still works
Change-Id: I32a24f237a4b1b89df23c982fe06566f30fec464
parent e9d43530
Loading
Loading
Loading
Loading
+52 −20
Original line number Original line Diff line number Diff line
@@ -1678,20 +1678,22 @@ public abstract class Layout {
    }
    }


    private void addSelection(int line, int start, int end,
    private void addSelection(int line, int start, int end,
                              int top, int bottom, Path dest) {
            int top, int bottom, RectangleConsumer consumer) {
        int linestart = getLineStart(line);
        int linestart = getLineStart(line);
        int lineend = getLineEnd(line);
        int lineend = getLineEnd(line);
        Directions dirs = getLineDirections(line);
        Directions dirs = getLineDirections(line);


        if (lineend > linestart && mText.charAt(lineend - 1) == '\n')
        if (lineend > linestart && mText.charAt(lineend - 1) == '\n') {
            lineend--;
            lineend--;
        }


        for (int i = 0; i < dirs.mDirections.length; i += 2) {
        for (int i = 0; i < dirs.mDirections.length; i += 2) {
            int here = linestart + dirs.mDirections[i];
            int here = linestart + dirs.mDirections[i];
            int there = here + (dirs.mDirections[i + 1] & RUN_LENGTH_MASK);
            int there = here + (dirs.mDirections[i + 1] & RUN_LENGTH_MASK);


            if (there > lineend)
            if (there > lineend) {
                there = lineend;
                there = lineend;
            }


            if (start <= there && end >= here) {
            if (start <= there && end >= here) {
                int st = Math.max(start, here);
                int st = Math.max(start, here);
@@ -1704,7 +1706,7 @@ public abstract class Layout {
                    float left = Math.min(h1, h2);
                    float left = Math.min(h1, h2);
                    float right = Math.max(h1, h2);
                    float right = Math.max(h1, h2);


                    dest.addRect(left, top, right, bottom, Path.Direction.CW);
                    consumer.accept(left, top, right, bottom);
                }
                }
            }
            }
        }
        }
@@ -1718,9 +1720,25 @@ public abstract class Layout {
     */
     */
    public void getSelectionPath(int start, int end, Path dest) {
    public void getSelectionPath(int start, int end, Path dest) {
        dest.reset();
        dest.reset();
        getSelection(start, end, (left, top, right, bottom) ->
                dest.addRect(left, top, right, bottom, Path.Direction.CW));
    }


        if (start == end)
    /**
     * Calculates the rectangles which should be highlighted to indicate a selection between start
     * and end and feeds them into the given {@link RectangleConsumer}.
     *
     * @param start    the starting index of the selection
     * @param end      the ending index of the selection
     * @param consumer the {@link RectangleConsumer} which will receive the generated rectangles. It
     *                 will be called every time a rectangle is generated.
     * @hide
     * @see #getSelectionPath(int, int, Path)
     */
    public final void getSelection(int start, int end, final RectangleConsumer consumer) {
        if (start == end) {
            return;
            return;
        }


        if (end < start) {
        if (end < start) {
            int temp = end;
            int temp = end;
@@ -1735,35 +1753,35 @@ public abstract class Layout {
        int bottom = getLineBottomWithoutSpacing(endline);
        int bottom = getLineBottomWithoutSpacing(endline);


        if (startline == endline) {
        if (startline == endline) {
            addSelection(startline, start, end, top, bottom, dest);
            addSelection(startline, start, end, top, bottom, consumer);
        } else {
        } else {
            final float width = mWidth;
            final float width = mWidth;


            addSelection(startline, start, getLineEnd(startline),
            addSelection(startline, start, getLineEnd(startline),
                         top, getLineBottom(startline), dest);
                    top, getLineBottom(startline), consumer);


            if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT)
            if (getParagraphDirection(startline) == DIR_RIGHT_TO_LEFT) {
                dest.addRect(getLineLeft(startline), top,
                consumer.accept(getLineLeft(startline), top, 0, getLineBottom(startline));
                              0, getLineBottom(startline), Path.Direction.CW);
            } else {
            else
                consumer.accept(getLineRight(startline), top, width, getLineBottom(startline));
                dest.addRect(getLineRight(startline), top,
            }
                              width, getLineBottom(startline), Path.Direction.CW);


            for (int i = startline + 1; i < endline; i++) {
            for (int i = startline + 1; i < endline; i++) {
                top = getLineTop(i);
                top = getLineTop(i);
                bottom = getLineBottom(i);
                bottom = getLineBottom(i);
                dest.addRect(0, top, width, bottom, Path.Direction.CW);
                consumer.accept(0, top, width, bottom);
            }
            }


            top = getLineTop(endline);
            top = getLineTop(endline);
            bottom = getLineBottomWithoutSpacing(endline);
            bottom = getLineBottomWithoutSpacing(endline);


            addSelection(endline, getLineStart(endline), end, top, bottom, dest);
            addSelection(endline, getLineStart(endline), end, top, bottom, consumer);


            if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT)
            if (getParagraphDirection(endline) == DIR_RIGHT_TO_LEFT) {
                dest.addRect(width, top, getLineRight(endline), bottom, Path.Direction.CW);
                consumer.accept(width, top, getLineRight(endline), bottom);
            else
            } else {
                dest.addRect(0, top, getLineLeft(endline), bottom, Path.Direction.CW);
                consumer.accept(0, top, getLineLeft(endline), bottom);
            }
        }
        }
    }
    }


@@ -2262,4 +2280,18 @@ public abstract class Layout {
    public static final Directions DIRS_ALL_RIGHT_TO_LEFT =
    public static final Directions DIRS_ALL_RIGHT_TO_LEFT =
        new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });
        new Directions(new int[] { 0, RUN_LENGTH_MASK | RUN_RTL_FLAG });


    /** @hide */
    @FunctionalInterface
    public interface RectangleConsumer {
        /**
         * Performs this operation on the given rectangle.
         *
         * @param left   the left edge of the rectangle
         * @param top    the top edge of the rectangle
         * @param right  the right edge of the rectangle
         * @param bottom the bottom edge of the rectangle
         */
        void accept(float left, float top, float right, float bottom);
    }

}
}