Merge "TextView cursor and selection improvements." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
50662f5f04
@@ -6549,12 +6549,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
int selEnd = getSelectionEnd();
|
int selEnd = getSelectionEnd();
|
||||||
|
|
||||||
if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
|
if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
|
||||||
|
// If a tap was used to give focus to that view, move cursor at tap position.
|
||||||
// Has to be done before onTakeFocus, which can be overloaded.
|
// Has to be done before onTakeFocus, which can be overloaded.
|
||||||
if (mLastTouchOffset >= 0) {
|
moveCursorToLastTapPosition();
|
||||||
// Can happen when a TextView is displayed after its content has been deleted.
|
|
||||||
mLastTouchOffset = Math.min(mLastTouchOffset, mText.length());
|
|
||||||
Selection.setSelection((Spannable) mText, mLastTouchOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mMovement != null) {
|
if (mMovement != null) {
|
||||||
mMovement.onTakeFocus(this, (Spannable) mText, direction);
|
mMovement.onTakeFocus(this, (Spannable) mText, direction);
|
||||||
@@ -6613,8 +6610,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
} else {
|
} else {
|
||||||
terminateTextSelectionMode();
|
terminateTextSelectionMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastTouchOffset = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startStopMarquee(focused);
|
startStopMarquee(focused);
|
||||||
@@ -6626,6 +6621,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void moveCursorToLastTapPosition() {
|
||||||
|
if (mSelectionModifierCursorController != null) {
|
||||||
|
int mTapToFocusPosition = ((SelectionModifierCursorController)
|
||||||
|
mSelectionModifierCursorController).getMinTouchOffset();
|
||||||
|
if (mTapToFocusPosition >= 0) {
|
||||||
|
// Safety check, should not be possible.
|
||||||
|
if (mTapToFocusPosition > mText.length()) {
|
||||||
|
Log.e(LOG_TAG, "Invalid tap focus position (" + mTapToFocusPosition + " vs "
|
||||||
|
+ mText.length() + ")");
|
||||||
|
mTapToFocusPosition = mText.length();
|
||||||
|
}
|
||||||
|
Selection.setSelection((Spannable) mText, mTapToFocusPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||||
super.onWindowFocusChanged(hasWindowFocus);
|
super.onWindowFocusChanged(hasWindowFocus);
|
||||||
@@ -6717,7 +6728,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
// Tapping outside stops selection mode, if any
|
// Tapping outside stops selection mode, if any
|
||||||
stopTextSelectionMode();
|
stopTextSelectionMode();
|
||||||
|
|
||||||
if (mInsertionPointCursorController != null) {
|
if (mInsertionPointCursorController != null && mText.length() > 0) {
|
||||||
mInsertionPointCursorController.show();
|
mInsertionPointCursorController.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7255,7 +7266,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
int minOffset, maxOffset;
|
int minOffset, maxOffset;
|
||||||
|
|
||||||
if (mDPadCenterIsDown || mEnterKeyIsDown) {
|
if (mContextMenuTriggeredByKey) {
|
||||||
minOffset = getSelectionStart();
|
minOffset = getSelectionStart();
|
||||||
maxOffset = getSelectionEnd();
|
maxOffset = getSelectionEnd();
|
||||||
} else {
|
} else {
|
||||||
@@ -7286,6 +7297,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getWordForDictionary() {
|
private String getWordForDictionary() {
|
||||||
|
if (!mContextMenuTriggeredByKey) {
|
||||||
|
moveCursorToLastTapPosition();
|
||||||
|
}
|
||||||
long wordLimits = getWordLimitsAt(getSelectionStart());
|
long wordLimits = getWordLimitsAt(getSelectionStart());
|
||||||
if (wordLimits >= 0) {
|
if (wordLimits >= 0) {
|
||||||
int start = extractRangeStartFromLong(wordLimits);
|
int start = extractRangeStartFromLong(wordLimits);
|
||||||
@@ -7336,6 +7350,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
protected void onCreateContextMenu(ContextMenu menu) {
|
protected void onCreateContextMenu(ContextMenu menu) {
|
||||||
super.onCreateContextMenu(menu);
|
super.onCreateContextMenu(menu);
|
||||||
boolean added = false;
|
boolean added = false;
|
||||||
|
mContextMenuTriggeredByKey = mDPadCenterIsDown || mEnterKeyIsDown;
|
||||||
|
// Problem with context menu on long press: the menu appears while the key in down and when
|
||||||
|
// the key is released, the view does not receive the key_up event. This ensures that the
|
||||||
|
// state is reset whenever the context menu action is displayed.
|
||||||
|
// mContextMenuTriggeredByKey saved that state so that it is available in
|
||||||
|
// onTextContextMenuItem. We cannot simply clear these flags in onTextContextMenuItem since
|
||||||
|
// it may not be called (if the user/ discards the context menu with the back key).
|
||||||
|
mDPadCenterIsDown = mEnterKeyIsDown = false;
|
||||||
|
|
||||||
if (mIsInTextSelectionMode) {
|
if (mIsInTextSelectionMode) {
|
||||||
MenuHandler handler = new MenuHandler();
|
MenuHandler handler = new MenuHandler();
|
||||||
@@ -7361,21 +7383,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
|
||||||
if (!isFocused()) {
|
|
||||||
if (isFocusable() && mInput != null) {
|
|
||||||
if (canCopy()) {
|
|
||||||
MenuHandler handler = new MenuHandler();
|
|
||||||
menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
|
|
||||||
setOnMenuItemClickListener(handler).
|
|
||||||
setAlphabeticShortcut('c');
|
|
||||||
menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
MenuHandler handler = new MenuHandler();
|
MenuHandler handler = new MenuHandler();
|
||||||
|
|
||||||
if (canSelectText()) {
|
if (canSelectText()) {
|
||||||
@@ -7529,7 +7536,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
case ID_ADD_TO_DICTIONARY:
|
case ID_ADD_TO_DICTIONARY:
|
||||||
String word = getWordForDictionary();
|
String word = getWordForDictionary();
|
||||||
|
|
||||||
if (word != null) {
|
if (word != null) {
|
||||||
Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
|
Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
|
||||||
i.putExtra("word", word);
|
i.putExtra("word", word);
|
||||||
@@ -8013,6 +8019,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
SelectionModifierCursorController() {
|
SelectionModifierCursorController() {
|
||||||
mStartHandle = new HandleView(this, HandleView.LEFT);
|
mStartHandle = new HandleView(this, HandleView.LEFT);
|
||||||
mEndHandle = new HandleView(this, HandleView.RIGHT);
|
mEndHandle = new HandleView(this, HandleView.RIGHT);
|
||||||
|
mMinTouchOffset = mMaxTouchOffset = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show() {
|
public void show() {
|
||||||
@@ -8095,14 +8102,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
if (isFocused() && isTextEditable()) {
|
// This is done even when the View does not have focus, so that long presses can start
|
||||||
|
// selection and tap can move cursor from this tap position.
|
||||||
|
if (isTextEditable()) {
|
||||||
switch (event.getActionMasked()) {
|
switch (event.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
final int x = (int) event.getX();
|
final int x = (int) event.getX();
|
||||||
final int y = (int) event.getY();
|
final int y = (int) event.getY();
|
||||||
|
|
||||||
// Remember finger down position, to be able to start selection from there
|
// Remember finger down position, to be able to start selection from there
|
||||||
mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y);
|
mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -8259,11 +8268,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
private CursorController mInsertionPointCursorController;
|
private CursorController mInsertionPointCursorController;
|
||||||
private CursorController mSelectionModifierCursorController;
|
private CursorController mSelectionModifierCursorController;
|
||||||
private boolean mIsInTextSelectionMode = false;
|
private boolean mIsInTextSelectionMode = false;
|
||||||
private int mLastTouchOffset = -1;
|
|
||||||
// These are needed to desambiguate a long click. If the long click comes from ones of these, we
|
// These are needed to desambiguate a long click. If the long click comes from ones of these, we
|
||||||
// select from the current cursor position. Otherwise, select from long pressed position.
|
// select from the current cursor position. Otherwise, select from long pressed position.
|
||||||
private boolean mDPadCenterIsDown = false;
|
private boolean mDPadCenterIsDown = false;
|
||||||
private boolean mEnterKeyIsDown = false;
|
private boolean mEnterKeyIsDown = false;
|
||||||
|
private boolean mContextMenuTriggeredByKey = false;
|
||||||
// Created once and shared by different CursorController helper methods.
|
// Created once and shared by different CursorController helper methods.
|
||||||
// Only one cursor controller is active at any time which prevent race conditions.
|
// Only one cursor controller is active at any time which prevent race conditions.
|
||||||
private static Rect sCursorControllerTempRect = new Rect();
|
private static Rect sCursorControllerTempRect = new Rect();
|
||||||
|
|||||||
Reference in New Issue
Block a user