Merge "Allow text selection handles to scroll horizontally" into mnc-dev
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e169ceb..010cb27 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4060,9 +4060,17 @@
private float mPrevX;
// Indicates if the handle has moved a boundary between LTR and RTL text.
private boolean mLanguageDirectionChanged = false;
+ // Distance from edge of horizontally scrolling text view
+ // to use to switch to character mode.
+ private final float mTextViewEdgeSlop;
+ // Used to save text view location.
+ private final int[] mTextViewLocation = new int[2];
public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(
+ mTextView.getContext());
+ mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
}
@Override
@@ -4100,7 +4108,7 @@
if (layout == null) {
// HandleView will deal appropriately in positionAtCursorOffset when
// layout is null.
- positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
+ positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
return;
}
@@ -4142,12 +4150,12 @@
// to the current position.
mLanguageDirectionChanged = true;
mTouchWordDelta = 0.0f;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
return;
} else if (mLanguageDirectionChanged && !isLvlBoundary) {
// We've just moved past the boundary so update the position. After this we can
// figure out if the user is expanding or shrinking to go by word or character.
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
mTouchWordDelta = 0.0f;
mLanguageDirectionChanged = false;
return;
@@ -4160,6 +4168,21 @@
}
}
+ if (mTextView.getHorizontallyScrolling()) {
+ if (positionNearEdgeOfScrollingView(x, atRtl)
+ && (mTextView.getScrollX() != 0)
+ && ((isExpanding && offset < selectionStart) || !isExpanding)) {
+ // If we're expanding ensure that the offset is smaller than the
+ // selection start, if the handle snapped to the word, the finger position
+ // may be out of sync and we don't want the selection to jump back.
+ mTouchWordDelta = 0.0f;
+ final int nextOffset = atRtl ? layout.getOffsetToRightOf(mPreviousOffset)
+ : layout.getOffsetToLeftOf(mPreviousOffset);
+ positionAndAdjustForCrossingHandles(nextOffset);
+ return;
+ }
+ }
+
if (isExpanding) {
// User is increasing the selection.
if (!mInWord || currLine < mPrevLine) {
@@ -4215,17 +4238,22 @@
}
if (positionCursor) {
- // Handles can not cross and selection is at least one character.
- if (offset >= selectionEnd) {
- offset = getNextCursorOffset(selectionEnd, false);
- mTouchWordDelta = 0.0f;
- }
mPreviousLineTouched = currLine;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
}
mPrevX = x;
}
+ private void positionAndAdjustForCrossingHandles(int offset) {
+ final int selectionEnd = mTextView.getSelectionEnd();
+ if (offset >= selectionEnd) {
+ // Handles can not cross and selection is at least one character.
+ offset = getNextCursorOffset(selectionEnd, false);
+ mTouchWordDelta = 0.0f;
+ }
+ positionAtCursorOffset(offset, false);
+ }
+
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
@@ -4243,6 +4271,20 @@
}
return superResult;
}
+
+ private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
+ mTextView.getLocationOnScreen(mTextViewLocation);
+ boolean nearEdge;
+ if (atRtl) {
+ int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
+ - mTextView.getPaddingRight();
+ nearEdge = x > rightEdge - mTextViewEdgeSlop;
+ } else {
+ int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
+ nearEdge = x < leftEdge + mTextViewEdgeSlop;
+ }
+ return nearEdge;
+ }
}
private class SelectionEndHandleView extends HandleView {
@@ -4254,9 +4296,17 @@
private float mPrevX;
// Indicates if the handle has moved a boundary between LTR and RTL text.
private boolean mLanguageDirectionChanged = false;
+ // Distance from edge of horizontally scrolling text view
+ // to use to switch to character mode.
+ private final float mTextViewEdgeSlop;
+ // Used to save the text view location.
+ private final int[] mTextViewLocation = new int[2];
public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
super(drawableLtr, drawableRtl);
+ ViewConfiguration viewConfiguration = ViewConfiguration.get(
+ mTextView.getContext());
+ mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
}
@Override
@@ -4294,7 +4344,7 @@
if (layout == null) {
// HandleView will deal appropriately in positionAtCursorOffset when
// layout is null.
- positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
+ positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
return;
}
@@ -4336,12 +4386,12 @@
// to the current position.
mLanguageDirectionChanged = true;
mTouchWordDelta = 0.0f;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
return;
} else if (mLanguageDirectionChanged && !isLvlBoundary) {
// We've just moved past the boundary so update the position. After this we can
// figure out if the user is expanding or shrinking to go by word or character.
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
mTouchWordDelta = 0.0f;
mLanguageDirectionChanged = false;
return;
@@ -4354,6 +4404,21 @@
}
}
+ if (mTextView.getHorizontallyScrolling()) {
+ if (positionNearEdgeOfScrollingView(x, atRtl)
+ && mTextView.canScrollHorizontally(atRtl ? -1 : 1)
+ && ((isExpanding && offset > selectionEnd) || !isExpanding)) {
+ // If we're expanding ensure that the offset is actually greater than the
+ // selection end, if the handle snapped to the word, the finger position
+ // may be out of sync and we don't want the selection to jump back.
+ mTouchWordDelta = 0.0f;
+ final int nextOffset = atRtl ? layout.getOffsetToLeftOf(mPreviousOffset)
+ : layout.getOffsetToRightOf(mPreviousOffset);
+ positionAndAdjustForCrossingHandles(nextOffset);
+ return;
+ }
+ }
+
if (isExpanding) {
// User is increasing the selection.
if (!mInWord || currLine > mPrevLine) {
@@ -4409,17 +4474,22 @@
}
if (positionCursor) {
- // Handles can not cross and selection is at least one character.
- if (offset <= selectionStart) {
- offset = getNextCursorOffset(selectionStart, true);
- mTouchWordDelta = 0.0f;
- }
mPreviousLineTouched = currLine;
- positionAtCursorOffset(offset, false);
+ positionAndAdjustForCrossingHandles(offset);
}
mPrevX = x;
}
+ private void positionAndAdjustForCrossingHandles(int offset) {
+ final int selectionStart = mTextView.getSelectionStart();
+ if (offset <= selectionStart) {
+ // Handles can not cross and selection is at least one character.
+ offset = getNextCursorOffset(selectionStart, true);
+ mTouchWordDelta = 0.0f;
+ }
+ positionAtCursorOffset(offset, false);
+ }
+
@Override
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
super.positionAtCursorOffset(offset, parentScrolled);
@@ -4437,6 +4507,20 @@
}
return superResult;
}
+
+ private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
+ mTextView.getLocationOnScreen(mTextViewLocation);
+ boolean nearEdge;
+ if (atRtl) {
+ int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
+ nearEdge = x < leftEdge + mTextViewEdgeSlop;
+ } else {
+ int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
+ - mTextView.getPaddingRight();
+ nearEdge = x > rightEdge - mTextViewEdgeSlop;
+ }
+ return nearEdge;
+ }
}
private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {