diff options
| author | Petar Šegina <psegina@google.com> | 2017-08-15 16:20:43 +0100 |
|---|---|---|
| committer | Petar Šegina <psegina@google.com> | 2017-08-23 19:20:12 +0100 |
| commit | 91df3f9e7c95d43d645e158b7d8fd34acc3385d3 (patch) | |
| tree | 59ffdb56f0c67dfab44d8223e32aa389d1875551 /core/java/android/widget/SelectionActionModeHelper.java | |
| parent | b2fb182085686ea72ee4a1364d0399ba236f4ec5 (diff) | |
Expand the animation from the user's last touch point
The Smart Select animation now expands from the spot the user last
lifted their finger.
In order to achieve this, the last up event coordinates need to be
tracked in Editor.
Since it's possible to trigger Smart Select by having the second of the
two taps outside any of the rectangles, the touch point gets moved into
the nearest rectangle and the animation starts from that point.
Test: manual - try out Smart Select by touching different words at
different points
Test: manual - try to trigger Smart Select with a double tap where the
second tap is outside of the word
Test: bit FrameworksCoreTests:android.widget.SelectionActionModeHelperTest
Test: bit CtsViewTestCases:android.view.textclassifier.cts.TextClassificationManagerTest
Test: bit FrameworksCoreTests:android.widget.TextViewActivityTest
Test: bit CtsAccessibilityServiceTestCases:android.accessibilityservice.cts.AccessibilityTextTraversalTest
Change-Id: I96844e8307554b010b476673820f98dae09c0cc3
Diffstat (limited to 'core/java/android/widget/SelectionActionModeHelper.java')
| -rw-r--r-- | core/java/android/widget/SelectionActionModeHelper.java | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 5e70ef0b973f..2561ffe572ab 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; import android.annotation.WorkerThread; +import android.graphics.PointF; import android.graphics.RectF; import android.os.AsyncTask; import android.os.LocaleList; @@ -27,13 +28,13 @@ import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.TextUtils; -import android.util.Pair; import android.view.ActionMode; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassifier; import android.view.textclassifier.TextSelection; import android.widget.Editor.SelectionModifierCursorController; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.ArrayList; @@ -45,8 +46,10 @@ import java.util.function.Supplier; /** * Helper class for starting selection action mode * (synchronously without the TextClassifier, asynchronously with the TextClassifier). + * @hide */ @UiThread +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) final class SelectionActionModeHelper { /** @@ -224,15 +227,15 @@ final class SelectionActionModeHelper { rectangle.bottom += textView.getPaddingTop(); } - final RectF firstRectangle = selectionRectangles.get(0); + final PointF touchPoint = new PointF( + mEditor.getLastUpPositionX(), + mEditor.getLastUpPositionY()); - // TODO use the original touch point instead of the hardcoded point generated here - final Pair<Float, Float> halfPoint = new Pair<>( - firstRectangle.centerX(), - firstRectangle.centerY()); + final PointF animationStartPoint = + movePointInsideNearestRectangle(touchPoint, selectionRectangles); mSmartSelectSprite.startAnimation( - halfPoint, + animationStartPoint, selectionRectangles, onAnimationEndCallback); } @@ -248,6 +251,39 @@ final class SelectionActionModeHelper { return result; } + /** @hide */ + @VisibleForTesting + public static PointF movePointInsideNearestRectangle(final PointF point, + final List<RectF> rectangles) { + float bestX = -1; + float bestY = -1; + double bestDistance = Double.MAX_VALUE; + + for (final RectF rectangle : rectangles) { + final float candidateY = rectangle.centerY(); + final float candidateX; + + if (point.x > rectangle.right) { + candidateX = rectangle.right; + } else if (point.x < rectangle.left) { + candidateX = rectangle.left; + } else { + candidateX = point.x; + } + + final double candidateDistance = Math.pow(point.x - candidateX, 2) + + Math.pow(point.y - candidateY, 2); + + if (candidateDistance < bestDistance) { + bestX = candidateX; + bestY = candidateY; + bestDistance = candidateDistance; + } + } + + return new PointF(bestX, bestY); + } + private void invalidateActionMode(@Nullable SelectionResult result) { cancelSmartSelectAnimation(); mTextClassification = result != null ? result.mClassification : null; |
