Skip to content

Commit beb6e66

Browse files
sliceslicebabyAndroid (Google) Code Review
authored andcommitted
Merge "Allow text selection handles to scroll horizontally" into mnc-dev
2 parents ee2a16b + 42390aa commit beb6e66

1 file changed

Lines changed: 102 additions & 18 deletions

File tree

core/java/android/widget/Editor.java

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4060,9 +4060,17 @@ private class SelectionStartHandleView extends HandleView {
40604060
private float mPrevX;
40614061
// Indicates if the handle has moved a boundary between LTR and RTL text.
40624062
private boolean mLanguageDirectionChanged = false;
4063+
// Distance from edge of horizontally scrolling text view
4064+
// to use to switch to character mode.
4065+
private final float mTextViewEdgeSlop;
4066+
// Used to save text view location.
4067+
private final int[] mTextViewLocation = new int[2];
40634068

40644069
public SelectionStartHandleView(Drawable drawableLtr, Drawable drawableRtl) {
40654070
super(drawableLtr, drawableRtl);
4071+
ViewConfiguration viewConfiguration = ViewConfiguration.get(
4072+
mTextView.getContext());
4073+
mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
40664074
}
40674075

40684076
@Override
@@ -4100,7 +4108,7 @@ public void updatePosition(float x, float y) {
41004108
if (layout == null) {
41014109
// HandleView will deal appropriately in positionAtCursorOffset when
41024110
// layout is null.
4103-
positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
4111+
positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
41044112
return;
41054113
}
41064114

@@ -4142,12 +4150,12 @@ public void updatePosition(float x, float y) {
41424150
// to the current position.
41434151
mLanguageDirectionChanged = true;
41444152
mTouchWordDelta = 0.0f;
4145-
positionAtCursorOffset(offset, false);
4153+
positionAndAdjustForCrossingHandles(offset);
41464154
return;
41474155
} else if (mLanguageDirectionChanged && !isLvlBoundary) {
41484156
// We've just moved past the boundary so update the position. After this we can
41494157
// figure out if the user is expanding or shrinking to go by word or character.
4150-
positionAtCursorOffset(offset, false);
4158+
positionAndAdjustForCrossingHandles(offset);
41514159
mTouchWordDelta = 0.0f;
41524160
mLanguageDirectionChanged = false;
41534161
return;
@@ -4160,6 +4168,21 @@ public void updatePosition(float x, float y) {
41604168
}
41614169
}
41624170

4171+
if (mTextView.getHorizontallyScrolling()) {
4172+
if (positionNearEdgeOfScrollingView(x, atRtl)
4173+
&& (mTextView.getScrollX() != 0)
4174+
&& ((isExpanding && offset < selectionStart) || !isExpanding)) {
4175+
// If we're expanding ensure that the offset is smaller than the
4176+
// selection start, if the handle snapped to the word, the finger position
4177+
// may be out of sync and we don't want the selection to jump back.
4178+
mTouchWordDelta = 0.0f;
4179+
final int nextOffset = atRtl ? layout.getOffsetToRightOf(mPreviousOffset)
4180+
: layout.getOffsetToLeftOf(mPreviousOffset);
4181+
positionAndAdjustForCrossingHandles(nextOffset);
4182+
return;
4183+
}
4184+
}
4185+
41634186
if (isExpanding) {
41644187
// User is increasing the selection.
41654188
if (!mInWord || currLine < mPrevLine) {
@@ -4215,17 +4238,22 @@ public void updatePosition(float x, float y) {
42154238
}
42164239

42174240
if (positionCursor) {
4218-
// Handles can not cross and selection is at least one character.
4219-
if (offset >= selectionEnd) {
4220-
offset = getNextCursorOffset(selectionEnd, false);
4221-
mTouchWordDelta = 0.0f;
4222-
}
42234241
mPreviousLineTouched = currLine;
4224-
positionAtCursorOffset(offset, false);
4242+
positionAndAdjustForCrossingHandles(offset);
42254243
}
42264244
mPrevX = x;
42274245
}
42284246

4247+
private void positionAndAdjustForCrossingHandles(int offset) {
4248+
final int selectionEnd = mTextView.getSelectionEnd();
4249+
if (offset >= selectionEnd) {
4250+
// Handles can not cross and selection is at least one character.
4251+
offset = getNextCursorOffset(selectionEnd, false);
4252+
mTouchWordDelta = 0.0f;
4253+
}
4254+
positionAtCursorOffset(offset, false);
4255+
}
4256+
42294257
@Override
42304258
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
42314259
super.positionAtCursorOffset(offset, parentScrolled);
@@ -4243,6 +4271,20 @@ public boolean onTouchEvent(MotionEvent event) {
42434271
}
42444272
return superResult;
42454273
}
4274+
4275+
private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
4276+
mTextView.getLocationOnScreen(mTextViewLocation);
4277+
boolean nearEdge;
4278+
if (atRtl) {
4279+
int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
4280+
- mTextView.getPaddingRight();
4281+
nearEdge = x > rightEdge - mTextViewEdgeSlop;
4282+
} else {
4283+
int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
4284+
nearEdge = x < leftEdge + mTextViewEdgeSlop;
4285+
}
4286+
return nearEdge;
4287+
}
42464288
}
42474289

42484290
private class SelectionEndHandleView extends HandleView {
@@ -4254,9 +4296,17 @@ private class SelectionEndHandleView extends HandleView {
42544296
private float mPrevX;
42554297
// Indicates if the handle has moved a boundary between LTR and RTL text.
42564298
private boolean mLanguageDirectionChanged = false;
4299+
// Distance from edge of horizontally scrolling text view
4300+
// to use to switch to character mode.
4301+
private final float mTextViewEdgeSlop;
4302+
// Used to save the text view location.
4303+
private final int[] mTextViewLocation = new int[2];
42574304

42584305
public SelectionEndHandleView(Drawable drawableLtr, Drawable drawableRtl) {
42594306
super(drawableLtr, drawableRtl);
4307+
ViewConfiguration viewConfiguration = ViewConfiguration.get(
4308+
mTextView.getContext());
4309+
mTextViewEdgeSlop = viewConfiguration.getScaledTouchSlop() * 4;
42604310
}
42614311

42624312
@Override
@@ -4294,7 +4344,7 @@ public void updatePosition(float x, float y) {
42944344
if (layout == null) {
42954345
// HandleView will deal appropriately in positionAtCursorOffset when
42964346
// layout is null.
4297-
positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
4347+
positionAndAdjustForCrossingHandles(mTextView.getOffsetForPosition(x, y));
42984348
return;
42994349
}
43004350

@@ -4336,12 +4386,12 @@ public void updatePosition(float x, float y) {
43364386
// to the current position.
43374387
mLanguageDirectionChanged = true;
43384388
mTouchWordDelta = 0.0f;
4339-
positionAtCursorOffset(offset, false);
4389+
positionAndAdjustForCrossingHandles(offset);
43404390
return;
43414391
} else if (mLanguageDirectionChanged && !isLvlBoundary) {
43424392
// We've just moved past the boundary so update the position. After this we can
43434393
// figure out if the user is expanding or shrinking to go by word or character.
4344-
positionAtCursorOffset(offset, false);
4394+
positionAndAdjustForCrossingHandles(offset);
43454395
mTouchWordDelta = 0.0f;
43464396
mLanguageDirectionChanged = false;
43474397
return;
@@ -4354,6 +4404,21 @@ public void updatePosition(float x, float y) {
43544404
}
43554405
}
43564406

4407+
if (mTextView.getHorizontallyScrolling()) {
4408+
if (positionNearEdgeOfScrollingView(x, atRtl)
4409+
&& mTextView.canScrollHorizontally(atRtl ? -1 : 1)
4410+
&& ((isExpanding && offset > selectionEnd) || !isExpanding)) {
4411+
// If we're expanding ensure that the offset is actually greater than the
4412+
// selection end, if the handle snapped to the word, the finger position
4413+
// may be out of sync and we don't want the selection to jump back.
4414+
mTouchWordDelta = 0.0f;
4415+
final int nextOffset = atRtl ? layout.getOffsetToLeftOf(mPreviousOffset)
4416+
: layout.getOffsetToRightOf(mPreviousOffset);
4417+
positionAndAdjustForCrossingHandles(nextOffset);
4418+
return;
4419+
}
4420+
}
4421+
43574422
if (isExpanding) {
43584423
// User is increasing the selection.
43594424
if (!mInWord || currLine > mPrevLine) {
@@ -4409,17 +4474,22 @@ public void updatePosition(float x, float y) {
44094474
}
44104475

44114476
if (positionCursor) {
4412-
// Handles can not cross and selection is at least one character.
4413-
if (offset <= selectionStart) {
4414-
offset = getNextCursorOffset(selectionStart, true);
4415-
mTouchWordDelta = 0.0f;
4416-
}
44174477
mPreviousLineTouched = currLine;
4418-
positionAtCursorOffset(offset, false);
4478+
positionAndAdjustForCrossingHandles(offset);
44194479
}
44204480
mPrevX = x;
44214481
}
44224482

4483+
private void positionAndAdjustForCrossingHandles(int offset) {
4484+
final int selectionStart = mTextView.getSelectionStart();
4485+
if (offset <= selectionStart) {
4486+
// Handles can not cross and selection is at least one character.
4487+
offset = getNextCursorOffset(selectionStart, true);
4488+
mTouchWordDelta = 0.0f;
4489+
}
4490+
positionAtCursorOffset(offset, false);
4491+
}
4492+
44234493
@Override
44244494
protected void positionAtCursorOffset(int offset, boolean parentScrolled) {
44254495
super.positionAtCursorOffset(offset, parentScrolled);
@@ -4437,6 +4507,20 @@ public boolean onTouchEvent(MotionEvent event) {
44374507
}
44384508
return superResult;
44394509
}
4510+
4511+
private boolean positionNearEdgeOfScrollingView(float x, boolean atRtl) {
4512+
mTextView.getLocationOnScreen(mTextViewLocation);
4513+
boolean nearEdge;
4514+
if (atRtl) {
4515+
int leftEdge = mTextViewLocation[0] + mTextView.getPaddingLeft();
4516+
nearEdge = x < leftEdge + mTextViewEdgeSlop;
4517+
} else {
4518+
int rightEdge = mTextViewLocation[0] + mTextView.getWidth()
4519+
- mTextView.getPaddingRight();
4520+
nearEdge = x > rightEdge - mTextViewEdgeSlop;
4521+
}
4522+
return nearEdge;
4523+
}
44404524
}
44414525

44424526
private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {

0 commit comments

Comments
 (0)