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

Commit 5ab7bb24 authored by Petar Šegina's avatar Petar Šegina
Browse files

Draw SmartSelectSprite in TextView

Instead of the SmartSelectSprite drawing its contents into a View's
ViewOverlay, the SmartSelectSprite can now be drawn on any Canvas. In
order to perform the smart select animation, it is now the TextView that
performs the actual drawing.

Since the TextView can adjust the canvas for its padding and offset,
there is no more need to manually transform the selection rectangles, so
that part can be removed.

Test: manual - verify smart select animation still works
Change-Id: Ibaccf59fd44d5701e6f37d6b4fa97f2b05fd77cc
parent cc782999
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1689,6 +1689,10 @@ public class Editor {
        } else {
            layout.draw(canvas, highlight, highlightPaint, cursorOffsetVertical);
        }

        if (mSelectionActionModeHelper != null) {
            mSelectionActionModeHelper.onDraw(canvas);
        }
    }

    private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight,
+12 −14
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.annotation.UiThread;
import android.annotation.WorkerThread;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.AsyncTask;
@@ -73,6 +74,9 @@ final class SelectionActionModeHelper {
    private AsyncTask mTextClassificationAsyncTask;

    private final SelectionTracker mSelectionTracker;

    // TODO remove nullable marker once the switch gating the feature gets removed
    @Nullable
    private final SmartSelectSprite mSmartSelectSprite;

    SelectionActionModeHelper(@NonNull Editor editor) {
@@ -85,7 +89,8 @@ final class SelectionActionModeHelper {
                new SelectionTracker(mTextView.getContext(), mTextView.isTextEditable());

        if (SMART_SELECT_ANIMATION_ENABLED) {
            mSmartSelectSprite = new SmartSelectSprite(mTextView);
            mSmartSelectSprite = new SmartSelectSprite(mTextView.getContext(),
                    mTextView::invalidate);
        } else {
            mSmartSelectSprite = null;
        }
@@ -167,6 +172,12 @@ final class SelectionActionModeHelper {
        cancelAsyncTask();
    }

    public void onDraw(final Canvas canvas) {
        if (mSmartSelectSprite != null) {
            mSmartSelectSprite.draw(canvas);
        }
    }

    private void cancelAsyncTask() {
        if (mTextClassificationAsyncTask != null) {
            mTextClassificationAsyncTask.cancel(true);
@@ -235,19 +246,6 @@ final class SelectionActionModeHelper {
            return;
        }

        /*
         * TODO Figure out a more robust approach for this
         * We have to translate all the generated rectangles by the top-left padding of the
         * TextView because the padding influences the rendering of the ViewOverlay, but is not
         * taken into account when generating the selection path rectangles.
         */
        for (RectF rectangle : selectionRectangles) {
            rectangle.left += mTextView.getPaddingLeft();
            rectangle.right += mTextView.getPaddingLeft();
            rectangle.top += mTextView.getPaddingTop();
            rectangle.bottom += mTextView.getPaddingTop();
        }

        final PointF touchPoint = new PointF(
                mEditor.getLastUpPositionX(),
                mEditor.getLastUpPositionY());
+19 −13
Original line number Diff line number Diff line
@@ -36,11 +36,11 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewOverlay;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;

import com.android.internal.util.Preconditions;

import java.lang.annotation.Retention;
import java.util.Collections;
import java.util.Comparator;
@@ -50,7 +50,6 @@ import java.util.List;
/**
 * A utility class for creating and animating the Smart Select animation.
 */
// TODO Do not rely on ViewOverlays for drawing the Smart Select sprite
final class SmartSelectSprite {

    private static final int EXPAND_DURATION = 300;
@@ -65,8 +64,8 @@ final class SmartSelectSprite {
    private final Interpolator mCornerInterpolator;
    private final float mStrokeWidth;

    private final View mView;
    private Animator mActiveAnimator = null;
    private final Runnable mInvalidator;
    @ColorInt
    private final int mStrokeColor;

@@ -331,8 +330,12 @@ final class SmartSelectSprite {

    }

    SmartSelectSprite(final View view) {
        final Context context = view.getContext();
    /**
     * @param context     The {@link Context} in which the animation will run
     * @param invalidator A {@link Runnable} which will be called every time the animation updates,
     *                    indicating that the view drawing the animation should invalidate itself
     */
    SmartSelectSprite(final Context context, final Runnable invalidator) {
        mExpandInterpolator = AnimationUtils.loadInterpolator(
                context,
                android.R.interpolator.fast_out_slow_in);
@@ -341,7 +344,7 @@ final class SmartSelectSprite {
                android.R.interpolator.fast_out_linear_in);
        mStrokeWidth = dpToPixel(context, STROKE_WIDTH_DP);
        mStrokeColor = getStrokeColor(context);
        mView = view;
        mInvalidator = Preconditions.checkNotNull(invalidator);
    }

    /**
@@ -366,7 +369,7 @@ final class SmartSelectSprite {
        cancelAnimation();

        final ValueAnimator.AnimatorUpdateListener updateListener =
                valueAnimator -> mView.invalidate();
                valueAnimator -> mInvalidator.run();

        final List<RoundedRectangleShape> shapes = new LinkedList<>();
        final List<Animator> cornerAnimators = new LinkedList<>();
@@ -421,7 +424,6 @@ final class SmartSelectSprite {

        mExistingRectangleList = rectangleList;
        mExistingDrawable = shapeDrawable;
        mView.getOverlay().add(shapeDrawable);

        mActiveAnimator = createAnimator(rectangleList, startingOffsetLeft, startingOffsetRight,
                cornerAnimators, updateListener,
@@ -480,7 +482,7 @@ final class SmartSelectSprite {
            @Override
            public void onAnimationEnd(Animator animator) {
                mExistingRectangleList.setDisplayType(RectangleList.DisplayType.POLYGON);
                mExistingDrawable.invalidateSelf();
                mInvalidator.run();

                onAnimationEnd.run();
            }
@@ -581,11 +583,9 @@ final class SmartSelectSprite {
    }

    private void removeExistingDrawables() {
        final ViewOverlay overlay = mView.getOverlay();
        overlay.remove(mExistingDrawable);

        mExistingDrawable = null;
        mExistingRectangleList = null;
        mInvalidator.run();
    }

    /**
@@ -599,4 +599,10 @@ final class SmartSelectSprite {
        }
    }

    public void draw(Canvas canvas) {
        if (mExistingDrawable != null) {
            mExistingDrawable.draw(canvas);
        }
    }

}