Loading core/java/android/widget/Editor.java +4 −0 Original line number Diff line number Diff line Loading @@ -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, Loading core/java/android/widget/SelectionActionModeHelper.java +12 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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()); Loading core/java/android/widget/SmartSelectSprite.java +19 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); } /** Loading @@ -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<>(); Loading Loading @@ -421,7 +424,6 @@ final class SmartSelectSprite { mExistingRectangleList = rectangleList; mExistingDrawable = shapeDrawable; mView.getOverlay().add(shapeDrawable); mActiveAnimator = createAnimator(rectangleList, startingOffsetLeft, startingOffsetRight, cornerAnimators, updateListener, Loading Loading @@ -480,7 +482,7 @@ final class SmartSelectSprite { @Override public void onAnimationEnd(Animator animator) { mExistingRectangleList.setDisplayType(RectangleList.DisplayType.POLYGON); mExistingDrawable.invalidateSelf(); mInvalidator.run(); onAnimationEnd.run(); } Loading Loading @@ -581,11 +583,9 @@ final class SmartSelectSprite { } private void removeExistingDrawables() { final ViewOverlay overlay = mView.getOverlay(); overlay.remove(mExistingDrawable); mExistingDrawable = null; mExistingRectangleList = null; mInvalidator.run(); } /** Loading @@ -599,4 +599,10 @@ final class SmartSelectSprite { } } public void draw(Canvas canvas) { if (mExistingDrawable != null) { mExistingDrawable.draw(canvas); } } } Loading
core/java/android/widget/Editor.java +4 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
core/java/android/widget/SelectionActionModeHelper.java +12 −14 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading @@ -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; } Loading Loading @@ -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); Loading Loading @@ -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()); Loading
core/java/android/widget/SmartSelectSprite.java +19 −13 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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); } /** Loading @@ -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<>(); Loading Loading @@ -421,7 +424,6 @@ final class SmartSelectSprite { mExistingRectangleList = rectangleList; mExistingDrawable = shapeDrawable; mView.getOverlay().add(shapeDrawable); mActiveAnimator = createAnimator(rectangleList, startingOffsetLeft, startingOffsetRight, cornerAnimators, updateListener, Loading Loading @@ -480,7 +482,7 @@ final class SmartSelectSprite { @Override public void onAnimationEnd(Animator animator) { mExistingRectangleList.setDisplayType(RectangleList.DisplayType.POLYGON); mExistingDrawable.invalidateSelf(); mInvalidator.run(); onAnimationEnd.run(); } Loading Loading @@ -581,11 +583,9 @@ final class SmartSelectSprite { } private void removeExistingDrawables() { final ViewOverlay overlay = mView.getOverlay(); overlay.remove(mExistingDrawable); mExistingDrawable = null; mExistingRectangleList = null; mInvalidator.run(); } /** Loading @@ -599,4 +599,10 @@ final class SmartSelectSprite { } } public void draw(Canvas canvas) { if (mExistingDrawable != null) { mExistingDrawable.draw(canvas); } } }