Merge "Separate the SelectionActionMode into Insertion and Selection." into mnc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c1f28bc97d
@@ -41542,6 +41542,7 @@ package android.widget {
|
||||
method public int getCompoundPaddingTop();
|
||||
method public final int getCurrentHintTextColor();
|
||||
method public final int getCurrentTextColor();
|
||||
method public android.view.ActionMode.Callback getCustomInsertionActionModeCallback();
|
||||
method public android.view.ActionMode.Callback getCustomSelectionActionModeCallback();
|
||||
method protected boolean getDefaultEditable();
|
||||
method protected android.text.method.MovementMethod getDefaultMovementMethod();
|
||||
@@ -41644,6 +41645,7 @@ package android.widget {
|
||||
method public void setCompoundDrawablesWithIntrinsicBounds(int, int, int, int);
|
||||
method public void setCompoundDrawablesWithIntrinsicBounds(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
|
||||
method public void setCursorVisible(boolean);
|
||||
method public void setCustomInsertionActionModeCallback(android.view.ActionMode.Callback);
|
||||
method public void setCustomSelectionActionModeCallback(android.view.ActionMode.Callback);
|
||||
method public final void setEditableFactory(android.text.Editable.Factory);
|
||||
method public void setElegantTextHeight(boolean);
|
||||
|
||||
@@ -44121,6 +44121,7 @@ package android.widget {
|
||||
method public int getCompoundPaddingTop();
|
||||
method public final int getCurrentHintTextColor();
|
||||
method public final int getCurrentTextColor();
|
||||
method public android.view.ActionMode.Callback getCustomInsertionActionModeCallback();
|
||||
method public android.view.ActionMode.Callback getCustomSelectionActionModeCallback();
|
||||
method protected boolean getDefaultEditable();
|
||||
method protected android.text.method.MovementMethod getDefaultMovementMethod();
|
||||
@@ -44223,6 +44224,7 @@ package android.widget {
|
||||
method public void setCompoundDrawablesWithIntrinsicBounds(int, int, int, int);
|
||||
method public void setCompoundDrawablesWithIntrinsicBounds(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
|
||||
method public void setCursorVisible(boolean);
|
||||
method public void setCustomInsertionActionModeCallback(android.view.ActionMode.Callback);
|
||||
method public void setCustomSelectionActionModeCallback(android.view.ActionMode.Callback);
|
||||
method public final void setEditableFactory(android.text.Editable.Factory);
|
||||
method public void setElegantTextHeight(boolean);
|
||||
|
||||
@@ -106,7 +106,7 @@ public class ExtractEditText extends EditText {
|
||||
if (mIME != null && mIME.onExtractTextContextMenuItem(id)) {
|
||||
// Mode was started on Extracted, needs to be stopped here.
|
||||
// Cut and paste will change the text, which stops selection mode.
|
||||
if (id == android.R.id.copy) stopSelectionActionMode();
|
||||
if (id == android.R.id.copy) stopTextActionMode();
|
||||
return true;
|
||||
}
|
||||
return super.onTextContextMenuItem(id);
|
||||
|
||||
@@ -134,7 +134,8 @@ public class Editor {
|
||||
// Cursor Controllers.
|
||||
InsertionPointCursorController mInsertionPointCursorController;
|
||||
SelectionModifierCursorController mSelectionModifierCursorController;
|
||||
ActionMode mSelectionActionMode;
|
||||
// Action mode used when text is selected or when actions on an insertion cursor are triggered.
|
||||
ActionMode mTextActionMode;
|
||||
boolean mInsertionControllerEnabled;
|
||||
boolean mSelectionControllerEnabled;
|
||||
|
||||
@@ -205,13 +206,14 @@ public class Editor {
|
||||
|
||||
float mLastDownPositionX, mLastDownPositionY;
|
||||
Callback mCustomSelectionActionModeCallback;
|
||||
Callback mCustomInsertionActionModeCallback;
|
||||
|
||||
// Set when this TextView gained focus with some text selected. Will start selection mode.
|
||||
boolean mCreatedWithASelection;
|
||||
|
||||
boolean mDoubleTap = false;
|
||||
|
||||
private Runnable mSelectionModeWithoutSelectionRunnable;
|
||||
private Runnable mInsertionActionModeRunnable;
|
||||
|
||||
// The span controller helps monitoring the changes to which the Editor needs to react:
|
||||
// - EasyEditSpans, for which we have some UI to display on attach and on hide
|
||||
@@ -236,8 +238,8 @@ public class Editor {
|
||||
private final Runnable mHideFloatingToolbar = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.snooze(ActionMode.SNOOZE_TIME_DEFAULT);
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.snooze(ActionMode.SNOOZE_TIME_DEFAULT);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -245,8 +247,8 @@ public class Editor {
|
||||
private final Runnable mShowFloatingToolbar = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.snooze(0); // snooze off.
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.snooze(0); // snooze off.
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -310,7 +312,7 @@ public class Editor {
|
||||
|
||||
void replace() {
|
||||
int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
Selection.setSelection((Spannable) mTextView.getText(), middle);
|
||||
showSuggestions();
|
||||
}
|
||||
@@ -343,7 +345,7 @@ public class Editor {
|
||||
mTextView.setHasTransientState(false);
|
||||
|
||||
// We had an active selection from before, start the selection mode.
|
||||
startSelectionActionModeWithSelection();
|
||||
startSelectionActionMode();
|
||||
}
|
||||
|
||||
getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
|
||||
@@ -372,8 +374,8 @@ public class Editor {
|
||||
}
|
||||
|
||||
// Cancel the single tap delayed runnable.
|
||||
if (mSelectionModeWithoutSelectionRunnable != null) {
|
||||
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
|
||||
if (mInsertionActionModeRunnable != null) {
|
||||
mTextView.removeCallbacks(mInsertionActionModeRunnable);
|
||||
}
|
||||
|
||||
mTextView.removeCallbacks(mHideFloatingToolbar);
|
||||
@@ -390,7 +392,7 @@ public class Editor {
|
||||
|
||||
mPreserveDetachedSelection = true;
|
||||
hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
mPreserveDetachedSelection = false;
|
||||
mTemporaryDetach = false;
|
||||
}
|
||||
@@ -586,7 +588,7 @@ public class Editor {
|
||||
}
|
||||
|
||||
if (!mSelectionControllerEnabled) {
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
if (mSelectionModifierCursorController != null) {
|
||||
mSelectionModifierCursorController.onDetached();
|
||||
mSelectionModifierCursorController = null;
|
||||
@@ -984,14 +986,14 @@ public class Editor {
|
||||
mInsertionControllerEnabled) {
|
||||
final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
|
||||
mLastDownPositionY);
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
Selection.setSelection((Spannable) mTextView.getText(), offset);
|
||||
getInsertionController().show();
|
||||
startSelectionActionModeWithoutSelection();
|
||||
startInsertionActionMode();
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (!handled && mSelectionActionMode != null) {
|
||||
if (!handled && mTextActionMode != null) {
|
||||
if (touchPositionIsInSelection()) {
|
||||
// Start a drag
|
||||
final int start = mTextView.getSelectionStart();
|
||||
@@ -1001,9 +1003,9 @@ public class Editor {
|
||||
DragLocalState localState = new DragLocalState(mTextView, start, end);
|
||||
mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState,
|
||||
View.DRAG_FLAG_GLOBAL);
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
} else {
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
selectCurrentWordAndStartDrag();
|
||||
}
|
||||
handled = true;
|
||||
@@ -1101,12 +1103,12 @@ public class Editor {
|
||||
final int selStart = mTextView.getSelectionStart();
|
||||
final int selEnd = mTextView.getSelectionEnd();
|
||||
hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
|
||||
} else {
|
||||
if (mTemporaryDetach) mPreserveDetachedSelection = true;
|
||||
hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
if (mTemporaryDetach) mPreserveDetachedSelection = false;
|
||||
downgradeEasyCorrectionSpans();
|
||||
}
|
||||
@@ -1149,7 +1151,7 @@ public class Editor {
|
||||
// We do not hide the span controllers, since they can be added when a new text is
|
||||
// inserted into the text view (voice IME).
|
||||
hideCursorControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
}
|
||||
|
||||
private int getLastTapPosition() {
|
||||
@@ -1216,7 +1218,7 @@ public class Editor {
|
||||
}
|
||||
|
||||
private void updateFloatingToolbarVisibility(MotionEvent event) {
|
||||
if (mSelectionActionMode != null) {
|
||||
if (mTextActionMode != null) {
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
hideFloatingToolbar();
|
||||
@@ -1229,7 +1231,7 @@ public class Editor {
|
||||
}
|
||||
|
||||
private void hideFloatingToolbar() {
|
||||
if (mSelectionActionMode != null) {
|
||||
if (mTextActionMode != null) {
|
||||
mTextView.removeCallbacks(mShowFloatingToolbar);
|
||||
// Delay the "hide" a little bit just in case a "show" will happen almost immediately.
|
||||
mTextView.postDelayed(mHideFloatingToolbar, 100);
|
||||
@@ -1237,7 +1239,7 @@ public class Editor {
|
||||
}
|
||||
|
||||
private void showFloatingToolbar() {
|
||||
if (mSelectionActionMode != null) {
|
||||
if (mTextActionMode != null) {
|
||||
mTextView.removeCallbacks(mHideFloatingToolbar);
|
||||
// Delay "show" so it doesn't interfere with click confirmations
|
||||
// or double-clicks that could "dismiss" the floating toolbar.
|
||||
@@ -1701,26 +1703,20 @@ public class Editor {
|
||||
/**
|
||||
* @return true if the selection mode was actually started.
|
||||
*/
|
||||
private boolean startSelectionActionModeWithoutSelection() {
|
||||
private boolean startInsertionActionMode() {
|
||||
if (mInsertionActionModeRunnable != null) {
|
||||
mTextView.removeCallbacks(mInsertionActionModeRunnable);
|
||||
}
|
||||
if (extractedTextModeWillBeStarted()) {
|
||||
// Cancel the single tap delayed runnable.
|
||||
if (mSelectionModeWithoutSelectionRunnable != null) {
|
||||
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
stopTextActionMode();
|
||||
|
||||
if (mSelectionActionMode != null) {
|
||||
// Selection action mode is already started
|
||||
// TODO: revisit invocations to minimize this case.
|
||||
mSelectionActionMode.invalidate();
|
||||
return false;
|
||||
}
|
||||
ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
|
||||
mSelectionActionMode = mTextView.startActionMode(
|
||||
ActionMode.Callback actionModeCallback =
|
||||
new TextActionModeCallback(false /* hasSelection */);
|
||||
mTextActionMode = mTextView.startActionMode(
|
||||
actionModeCallback, ActionMode.TYPE_FLOATING);
|
||||
return mSelectionActionMode != null;
|
||||
return mTextActionMode != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1730,8 +1726,8 @@ public class Editor {
|
||||
*
|
||||
* @return true if the selection mode was actually started.
|
||||
*/
|
||||
boolean startSelectionActionModeWithSelection() {
|
||||
boolean selectionStarted = startSelectionActionModeWithSelectionInternal();
|
||||
boolean startSelectionActionMode() {
|
||||
boolean selectionStarted = startSelectionActionModeInternal();
|
||||
if (selectionStarted) {
|
||||
getSelectionController().show();
|
||||
} else if (getInsertionController() != null) {
|
||||
@@ -1749,13 +1745,13 @@ public class Editor {
|
||||
private boolean selectCurrentWordAndStartDrag() {
|
||||
if (extractedTextModeWillBeStarted()) {
|
||||
// Cancel the single tap delayed runnable.
|
||||
if (mSelectionModeWithoutSelectionRunnable != null) {
|
||||
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
|
||||
if (mInsertionActionModeRunnable != null) {
|
||||
mTextView.removeCallbacks(mInsertionActionModeRunnable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.finish();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.finish();
|
||||
}
|
||||
if (!checkFieldAndSelectCurrentWord()) {
|
||||
return false;
|
||||
@@ -1784,10 +1780,10 @@ public class Editor {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean startSelectionActionModeWithSelectionInternal() {
|
||||
if (mSelectionActionMode != null) {
|
||||
private boolean startSelectionActionModeInternal() {
|
||||
if (mTextActionMode != null) {
|
||||
// Selection action mode is already started
|
||||
mSelectionActionMode.invalidate();
|
||||
mTextActionMode.invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1800,12 +1796,13 @@ public class Editor {
|
||||
// Do not start the action mode when extracted text will show up full screen, which would
|
||||
// immediately hide the newly created action bar and would be visually distracting.
|
||||
if (!willExtract) {
|
||||
ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
|
||||
mSelectionActionMode = mTextView.startActionMode(
|
||||
ActionMode.Callback actionModeCallback =
|
||||
new TextActionModeCallback(true /* hasSelection */);
|
||||
mTextActionMode = mTextView.startActionMode(
|
||||
actionModeCallback, ActionMode.TYPE_FLOATING);
|
||||
}
|
||||
|
||||
final boolean selectionStarted = mSelectionActionMode != null || willExtract;
|
||||
final boolean selectionStarted = mTextActionMode != null || willExtract;
|
||||
if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) {
|
||||
// Show the IME to be able to replace text, except when selecting non editable text.
|
||||
final InputMethodManager imm = InputMethodManager.peekInstance();
|
||||
@@ -1906,7 +1903,7 @@ public class Editor {
|
||||
void onTouchUpEvent(MotionEvent event) {
|
||||
boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect();
|
||||
hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
CharSequence text = mTextView.getText();
|
||||
if (!selectAllGotFocus && text.length() > 0) {
|
||||
// Move cursor
|
||||
@@ -1920,8 +1917,8 @@ public class Editor {
|
||||
if (!extractedTextModeWillBeStarted()) {
|
||||
if (isCursorInsideEasyCorrectionSpan()) {
|
||||
// Cancel the single tap delayed runnable.
|
||||
if (mSelectionModeWithoutSelectionRunnable != null) {
|
||||
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
|
||||
if (mInsertionActionModeRunnable != null) {
|
||||
mTextView.removeCallbacks(mInsertionActionModeRunnable);
|
||||
}
|
||||
|
||||
mShowSuggestionRunnable = new Runnable() {
|
||||
@@ -1939,10 +1936,10 @@ public class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
protected void stopSelectionActionMode() {
|
||||
if (mSelectionActionMode != null) {
|
||||
protected void stopTextActionMode() {
|
||||
if (mTextActionMode != null) {
|
||||
// This will hide the mSelectionModifierCursorController
|
||||
mSelectionActionMode.finish();
|
||||
mTextActionMode.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2027,7 +2024,7 @@ public class Editor {
|
||||
mSuggestionsPopupWindow = new SuggestionsPopupWindow();
|
||||
}
|
||||
hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
mSuggestionsPopupWindow.show();
|
||||
}
|
||||
|
||||
@@ -2035,8 +2032,8 @@ public class Editor {
|
||||
if (mPositionListener != null) {
|
||||
mPositionListener.onScrollChanged();
|
||||
}
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.invalidateContentRect();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.invalidateContentRect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3087,45 +3084,51 @@ public class Editor {
|
||||
}
|
||||
|
||||
/**
|
||||
* An ActionMode Callback class that is used to provide actions while in text selection mode.
|
||||
* An ActionMode Callback class that is used to provide actions while in text insertion or
|
||||
* selection mode.
|
||||
*
|
||||
* The default callback provides a subset of Select All, Cut, Copy and Paste actions, depending
|
||||
* on which of these this TextView supports.
|
||||
* The default callback provides a subset of Select All, Cut, Copy, Paste, Share and Replace
|
||||
* actions, depending on which of these this TextView supports and the current selection.
|
||||
*/
|
||||
private class SelectionActionModeCallback extends ActionMode.Callback2 {
|
||||
private class TextActionModeCallback extends ActionMode.Callback2 {
|
||||
private final Path mSelectionPath = new Path();
|
||||
private final RectF mSelectionBounds = new RectF();
|
||||
private final boolean mHasSelection;
|
||||
|
||||
private int mSelectionHandleHeight;
|
||||
private int mInsertionHandleHeight;
|
||||
private int mHandleHeight;
|
||||
|
||||
public SelectionActionModeCallback() {
|
||||
SelectionModifierCursorController selectionController = getSelectionController();
|
||||
if (selectionController.mStartHandle == null) {
|
||||
// As these are for initializing selectionController, hide() must be called.
|
||||
selectionController.initDrawables();
|
||||
selectionController.initHandles();
|
||||
selectionController.hide();
|
||||
}
|
||||
mSelectionHandleHeight = Math.max(
|
||||
mSelectHandleLeft.getMinimumHeight(), mSelectHandleRight.getMinimumHeight());
|
||||
InsertionPointCursorController insertionController = getInsertionController();
|
||||
if (insertionController != null) {
|
||||
insertionController.getHandle();
|
||||
mInsertionHandleHeight = mSelectHandleCenter.getMinimumHeight();
|
||||
public TextActionModeCallback(boolean hasSelection) {
|
||||
mHasSelection = hasSelection;
|
||||
if (mHasSelection) {
|
||||
SelectionModifierCursorController selectionController = getSelectionController();
|
||||
if (selectionController.mStartHandle == null) {
|
||||
// As these are for initializing selectionController, hide() must be called.
|
||||
selectionController.initDrawables();
|
||||
selectionController.initHandles();
|
||||
selectionController.hide();
|
||||
}
|
||||
mHandleHeight = Math.max(
|
||||
mSelectHandleLeft.getMinimumHeight(),
|
||||
mSelectHandleRight.getMinimumHeight());
|
||||
} else {
|
||||
InsertionPointCursorController insertionController = getInsertionController();
|
||||
if (insertionController != null) {
|
||||
insertionController.getHandle();
|
||||
mHandleHeight = mSelectHandleCenter.getMinimumHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
mode.setTitle(mTextView.getContext().getString(
|
||||
com.android.internal.R.string.textSelectionCABTitle));
|
||||
mode.setTitle(null);
|
||||
mode.setSubtitle(null);
|
||||
mode.setTitleOptionalHint(true);
|
||||
populateMenuWithItems(menu);
|
||||
|
||||
if (mCustomSelectionActionModeCallback != null) {
|
||||
if (!mCustomSelectionActionModeCallback.onCreateActionMode(mode, menu)) {
|
||||
Callback customCallback = getCustomCallback();
|
||||
if (customCallback != null) {
|
||||
if (!customCallback.onCreateActionMode(mode, menu)) {
|
||||
// The custom mode can choose to cancel the action mode
|
||||
return false;
|
||||
}
|
||||
@@ -3141,6 +3144,12 @@ public class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
private Callback getCustomCallback() {
|
||||
return mHasSelection
|
||||
? mCustomSelectionActionModeCallback
|
||||
: mCustomInsertionActionModeCallback;
|
||||
}
|
||||
|
||||
private void populateMenuWithItems(Menu menu) {
|
||||
if (mTextView.canCut()) {
|
||||
menu.add(0, TextView.ID_CUT, 0, com.android.internal.R.string.cut).
|
||||
@@ -3203,8 +3212,9 @@ public class Editor {
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
updateReplaceItem(menu);
|
||||
|
||||
if (mCustomSelectionActionModeCallback != null) {
|
||||
return mCustomSelectionActionModeCallback.onPrepareActionMode(mode, menu);
|
||||
Callback customCallback = getCustomCallback();
|
||||
if (customCallback != null) {
|
||||
return customCallback.onPrepareActionMode(mode, menu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -3230,8 +3240,8 @@ public class Editor {
|
||||
item.getIntent(), TextView.PROCESS_TEXT_REQUEST_CODE);
|
||||
return true;
|
||||
}
|
||||
if (mCustomSelectionActionModeCallback != null &&
|
||||
mCustomSelectionActionModeCallback.onActionItemClicked(mode, item)) {
|
||||
Callback customCallback = getCustomCallback();
|
||||
if (customCallback != null && customCallback.onActionItemClicked(mode, item)) {
|
||||
return true;
|
||||
}
|
||||
return mTextView.onTextContextMenuItem(item.getItemId());
|
||||
@@ -3239,8 +3249,9 @@ public class Editor {
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
if (mCustomSelectionActionModeCallback != null) {
|
||||
mCustomSelectionActionModeCallback.onDestroyActionMode(mode);
|
||||
Callback customCallback = getCustomCallback();
|
||||
if (customCallback != null) {
|
||||
customCallback.onDestroyActionMode(mode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3259,7 +3270,7 @@ public class Editor {
|
||||
mSelectionModifierCursorController.resetTouchOffsets();
|
||||
}
|
||||
|
||||
mSelectionActionMode = null;
|
||||
mTextActionMode = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3274,7 +3285,7 @@ public class Editor {
|
||||
mTextView.getLayout().getSelectionPath(
|
||||
mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mSelectionPath);
|
||||
mSelectionPath.computeBounds(mSelectionBounds, true);
|
||||
mSelectionBounds.bottom += mSelectionHandleHeight;
|
||||
mSelectionBounds.bottom += mHandleHeight;
|
||||
} else if (mCursorCount == 2) {
|
||||
// We have a split cursor. In this case, we take the rectangle that includes both
|
||||
// parts of the cursor to ensure we don't obscure either of them.
|
||||
@@ -3285,7 +3296,7 @@ public class Editor {
|
||||
Math.min(firstCursorBounds.top, secondCursorBounds.top),
|
||||
Math.max(firstCursorBounds.right, secondCursorBounds.right),
|
||||
Math.max(firstCursorBounds.bottom, secondCursorBounds.bottom)
|
||||
+ mInsertionHandleHeight);
|
||||
+ mHandleHeight);
|
||||
} else {
|
||||
// We have a single cursor.
|
||||
int line = mTextView.getLayout().getLineForOffset(mTextView.getSelectionStart());
|
||||
@@ -3295,7 +3306,7 @@ public class Editor {
|
||||
primaryHorizontal,
|
||||
mTextView.getLayout().getLineTop(line),
|
||||
primaryHorizontal + 1,
|
||||
mTextView.getLayout().getLineTop(line + 1) + mInsertionHandleHeight);
|
||||
mTextView.getLayout().getLineTop(line + 1) + mHandleHeight);
|
||||
}
|
||||
// Take TextView's padding and scroll into account.
|
||||
int textHorizontalOffset = mTextView.viewportToContentHorizontalOffset();
|
||||
@@ -3847,25 +3858,25 @@ public class Editor {
|
||||
SystemClock.uptimeMillis() - TextView.sLastCutCopyOrTextChangedTime;
|
||||
|
||||
// Cancel the single tap delayed runnable.
|
||||
if (mSelectionModeWithoutSelectionRunnable != null
|
||||
if (mInsertionActionModeRunnable != null
|
||||
&& (mDoubleTap || isCursorInsideEasyCorrectionSpan())) {
|
||||
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
|
||||
mTextView.removeCallbacks(mInsertionActionModeRunnable);
|
||||
}
|
||||
|
||||
// Prepare and schedule the single tap runnable to run exactly after the double tap
|
||||
// timeout has passed.
|
||||
if (!mDoubleTap && !isCursorInsideEasyCorrectionSpan()
|
||||
&& (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)) {
|
||||
if (mSelectionModeWithoutSelectionRunnable == null) {
|
||||
mSelectionModeWithoutSelectionRunnable = new Runnable() {
|
||||
if (mInsertionActionModeRunnable == null) {
|
||||
mInsertionActionModeRunnable = new Runnable() {
|
||||
public void run() {
|
||||
startSelectionActionModeWithoutSelection();
|
||||
startInsertionActionMode();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mTextView.postDelayed(
|
||||
mSelectionModeWithoutSelectionRunnable,
|
||||
mInsertionActionModeRunnable,
|
||||
ViewConfiguration.getDoubleTapTimeout() + 1);
|
||||
}
|
||||
|
||||
@@ -3934,15 +3945,15 @@ public class Editor {
|
||||
|
||||
if (distanceSquared < touchSlop * touchSlop) {
|
||||
// Tapping on the handle toggles the selection action mode.
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.finish();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.finish();
|
||||
} else {
|
||||
startSelectionActionModeWithoutSelection();
|
||||
startInsertionActionMode();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.invalidateContentRect();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.invalidateContentRect();
|
||||
}
|
||||
}
|
||||
hideAfterDelay();
|
||||
@@ -3972,8 +3983,8 @@ public class Editor {
|
||||
@Override
|
||||
public void updatePosition(float x, float y) {
|
||||
positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false);
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.invalidate();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4024,8 +4035,8 @@ public class Editor {
|
||||
Selection.setSelection((Spannable) mTextView.getText(), offset,
|
||||
mTextView.getSelectionEnd());
|
||||
updateDrawable();
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.invalidate();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4150,8 +4161,8 @@ public class Editor {
|
||||
public void updateSelection(int offset) {
|
||||
Selection.setSelection((Spannable) mTextView.getText(),
|
||||
mTextView.getSelectionStart(), offset);
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.invalidate();
|
||||
if (mTextActionMode != null) {
|
||||
mTextActionMode.invalidate();
|
||||
}
|
||||
updateDrawable();
|
||||
}
|
||||
@@ -4515,7 +4526,7 @@ public class Editor {
|
||||
mEndHandle.showAtLocation(endOffset);
|
||||
|
||||
// No longer the first dragging motion, reset.
|
||||
startSelectionActionModeWithSelection();
|
||||
startSelectionActionMode();
|
||||
mDragAcceleratorActive = false;
|
||||
mStartOffset = -1;
|
||||
}
|
||||
|
||||
@@ -1481,7 +1481,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
}
|
||||
}
|
||||
if (mEditor.hasSelectionController()) {
|
||||
mEditor.startSelectionActionModeWithSelection();
|
||||
mEditor.startSelectionActionMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5282,7 +5282,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
// - onFocusChanged cannot start it when focus is given to a view with selected text (after
|
||||
// a screen rotation) since layout is not yet initialized at that point.
|
||||
if (mEditor != null && mEditor.mCreatedWithASelection) {
|
||||
mEditor.startSelectionActionModeWithSelection();
|
||||
mEditor.startSelectionActionMode();
|
||||
mEditor.mCreatedWithASelection = false;
|
||||
}
|
||||
|
||||
@@ -5290,7 +5290,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
// ExtractEditText does not call onFocus when it is displayed, and mHasSelectionOnFocus can
|
||||
// not be set. Do the test here instead.
|
||||
if (this instanceof ExtractEditText && hasSelection() && mEditor != null) {
|
||||
mEditor.startSelectionActionModeWithSelection();
|
||||
mEditor.startSelectionActionMode();
|
||||
}
|
||||
|
||||
unregisterForPreDraw();
|
||||
@@ -5908,7 +5908,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
@Override
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
boolean isInSelectionMode = mEditor != null && mEditor.mSelectionActionMode != null;
|
||||
boolean isInSelectionMode = mEditor != null && mEditor.mTextActionMode != null;
|
||||
|
||||
if (isInSelectionMode) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
|
||||
@@ -5923,7 +5923,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
state.handleUpEvent(event);
|
||||
}
|
||||
if (event.isTracking() && !event.isCanceled()) {
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6092,8 +6092,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
|
||||
// Has to be done on key down (and not on key up) to correctly be intercepted.
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
if (mEditor != null && mEditor.mSelectionActionMode != null) {
|
||||
stopSelectionActionMode();
|
||||
if (mEditor != null && mEditor.mTextActionMode != null) {
|
||||
stopTextActionMode();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -6423,7 +6423,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
// extracted mode will start. Some text is selected though, and will trigger an action mode
|
||||
// in the extracted view.
|
||||
mEditor.hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8258,7 +8258,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
super.onVisibilityChanged(changedView, visibility);
|
||||
if (mEditor != null && visibility != VISIBLE) {
|
||||
mEditor.hideControllers();
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8976,7 +8976,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
Selection.setSelection((Spannable) text, start, end);
|
||||
// Make sure selection mode is engaged.
|
||||
if (mEditor != null) {
|
||||
mEditor.startSelectionActionModeWithSelection();
|
||||
mEditor.startSelectionActionMode();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -9100,12 +9100,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
case ID_CUT:
|
||||
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
|
||||
deleteText_internal(min, max);
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
return true;
|
||||
|
||||
case ID_COPY:
|
||||
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
return true;
|
||||
|
||||
case ID_REPLACE:
|
||||
@@ -9195,14 +9195,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
* selection is initiated in this View.
|
||||
*
|
||||
* The standard implementation populates the menu with a subset of Select All, Cut, Copy,
|
||||
* Paste and Share actions, depending on what this View supports.
|
||||
* Paste, Replace and Share actions, depending on what this View supports.
|
||||
*
|
||||
* A custom implementation can add new entries in the default menu in its
|
||||
* {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The
|
||||
* default actions can also be removed from the menu using
|
||||
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
|
||||
* {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste} or
|
||||
* {@link android.R.id#shareText} ids as parameters.
|
||||
* {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste},
|
||||
* {@link android.R.id#replaceText} or {@link android.R.id#shareText} ids as parameters.
|
||||
*
|
||||
* Returning false from
|
||||
* {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent
|
||||
@@ -9229,12 +9229,49 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
return mEditor == null ? null : mEditor.mCustomSelectionActionModeCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* If provided, this ActionMode.Callback will be used to create the ActionMode when text
|
||||
* insertion is initiated in this View.
|
||||
*
|
||||
* The standard implementation populates the menu with a subset of Select All,
|
||||
* Paste and Replace actions, depending on what this View supports.
|
||||
*
|
||||
* A custom implementation can add new entries in the default menu in its
|
||||
* {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The
|
||||
* default actions can also be removed from the menu using
|
||||
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
|
||||
* {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.
|
||||
*
|
||||
* Returning false from
|
||||
* {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent
|
||||
* the action mode from being started.
|
||||
*
|
||||
* Action click events should be handled by the custom implementation of
|
||||
* {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}.
|
||||
*
|
||||
* Note that text insertion mode is not started when a TextView receives focus and the
|
||||
* {@link android.R.attr#selectAllOnFocus} flag has been set.
|
||||
*/
|
||||
public void setCustomInsertionActionModeCallback(ActionMode.Callback actionModeCallback) {
|
||||
createEditorIfNeeded();
|
||||
mEditor.mCustomInsertionActionModeCallback = actionModeCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value set in {@link #setCustomInsertionActionModeCallback}. Default is null.
|
||||
*
|
||||
* @return The current custom insertion callback.
|
||||
*/
|
||||
public ActionMode.Callback getCustomInsertionActionModeCallback() {
|
||||
return mEditor == null ? null : mEditor.mCustomInsertionActionModeCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
protected void stopSelectionActionMode() {
|
||||
protected void stopTextActionMode() {
|
||||
if (mEditor != null) {
|
||||
mEditor.stopSelectionActionMode();
|
||||
mEditor.stopTextActionMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9346,7 +9383,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
}
|
||||
}
|
||||
}
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
sLastCutCopyOrTextChangedTime = 0;
|
||||
}
|
||||
}
|
||||
@@ -9359,7 +9396,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT);
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText);
|
||||
getContext().startActivity(Intent.createChooser(sharingIntent, null));
|
||||
stopSelectionActionMode();
|
||||
stopTextActionMode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user