summaryrefslogtreecommitdiff
path: root/core/java/android/widget/SelectionActionModeHelper.java
diff options
context:
space:
mode:
authorPetar Ĺ egina <psegina@google.com>2017-09-12 10:23:36 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-09-12 10:23:36 +0000
commit02b345725b663720a2bf9b5f947b5db83fa2649c (patch)
treea0052b73b022680cc6148031a398c55ef5f84165 /core/java/android/widget/SelectionActionModeHelper.java
parent2b219baf14c387ca752d9b7fdd0a93149b70574b (diff)
parentba1b8566e4b621f0acee3eeca3c0053647bdf5ab (diff)
Merge "Filter out empty and unnecessary rectangles"
Diffstat (limited to 'core/java/android/widget/SelectionActionModeHelper.java')
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java65
1 files changed, 58 insertions, 7 deletions
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 041b515f7e47..81a5eadf8173 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -56,7 +56,7 @@ import java.util.function.Supplier;
*/
@UiThread
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-final class SelectionActionModeHelper {
+public final class SelectionActionModeHelper {
/**
* Maximum time (in milliseconds) to wait for a result before timing out.
@@ -262,17 +262,66 @@ final class SelectionActionModeHelper {
private List<RectF> convertSelectionToRectangles(final Layout layout, final int start,
final int end) {
final List<RectF> result = new ArrayList<>();
- // TODO filter out invalid rectangles
- // getSelection might give us overlapping and zero-dimension rectangles which will interfere
- // with the Smart Select animation
layout.getSelection(start, end, (left, top, right, bottom, textSelectionLayout) ->
- result.add(new RectF(left, top, right, bottom)));
+ mergeRectangleIntoList(result, new RectF(left, top, right, bottom)));
result.sort(SmartSelectSprite.RECTANGLE_COMPARATOR);
-
return result;
}
+ /**
+ * Merges a {@link RectF} into an existing list of rectangles. While merging, this method
+ * makes sure that:
+ *
+ * <ol>
+ * <li>No rectangle is redundant (contained within a bigger rectangle)</li>
+ * <li>Rectangles of the same height and vertical position that intersect get merged</li>
+ * </ol>
+ *
+ * @param list the list of rectangles to merge the new rectangle in
+ * @param candidate the {@link RectF} to merge into the list
+ * @hide
+ */
+ @VisibleForTesting
+ public static void mergeRectangleIntoList(List<RectF> list, RectF candidate) {
+ if (candidate.isEmpty()) {
+ return;
+ }
+
+ final int elementCount = list.size();
+ for (int index = 0; index < elementCount; ++index) {
+ final RectF existingRectangle = list.get(index);
+ if (existingRectangle.contains(candidate)) {
+ return;
+ }
+ if (candidate.contains(existingRectangle)) {
+ existingRectangle.setEmpty();
+ continue;
+ }
+
+ final boolean rectanglesContinueEachOther = candidate.left == existingRectangle.right
+ || candidate.right == existingRectangle.left;
+ final boolean canMerge = candidate.top == existingRectangle.top
+ && candidate.bottom == existingRectangle.bottom
+ && (RectF.intersects(candidate, existingRectangle)
+ || rectanglesContinueEachOther);
+
+ if (canMerge) {
+ candidate.union(existingRectangle);
+ existingRectangle.setEmpty();
+ }
+ }
+
+ for (int index = elementCount - 1; index >= 0; --index) {
+ if (list.get(index).isEmpty()) {
+ list.remove(index);
+ }
+ }
+
+ list.add(candidate);
+ }
+
+
/** @hide */
@VisibleForTesting
public static PointF movePointInsideNearestRectangle(final PointF point,
@@ -281,7 +330,9 @@ final class SelectionActionModeHelper {
float bestY = -1;
double bestDistance = Double.MAX_VALUE;
- for (final RectF rectangle : rectangles) {
+ final int elementCount = rectangles.size();
+ for (int index = 0; index < elementCount; ++index) {
+ final RectF rectangle = rectangles.get(index);
final float candidateY = rectangle.centerY();
final float candidateX;