summaryrefslogtreecommitdiff
path: root/core/java/android/widget/SelectionActionModeHelper.java
diff options
context:
space:
mode:
authorPetar Šegina <psegina@google.com>2017-08-15 16:20:43 +0100
committerPetar Šegina <psegina@google.com>2017-08-23 19:20:12 +0100
commit91df3f9e7c95d43d645e158b7d8fd34acc3385d3 (patch)
tree59ffdb56f0c67dfab44d8223e32aa389d1875551 /core/java/android/widget/SelectionActionModeHelper.java
parentb2fb182085686ea72ee4a1364d0399ba236f4ec5 (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.java50
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;