summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--api/system-current.txt2
-rw-r--r--core/java/android/inputmethodservice/ExtractEditText.java2
-rw-r--r--core/java/android/widget/Editor.java237
-rw-r--r--core/java/android/widget/TextView.java75
5 files changed, 185 insertions, 133 deletions
diff --git a/api/current.txt b/api/current.txt
index c105345..51a1e79 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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);
diff --git a/api/system-current.txt b/api/system-current.txt
index 14c9939..7ce111c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -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);
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 48b604c..f965f54 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -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);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 56f9b5c..4c98abf 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -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 int mSelectionHandleHeight;
- private int mInsertionHandleHeight;
-
- 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();
+ private final boolean mHasSelection;
+
+ private int mHandleHeight;
+
+ 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;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3a85476..6872caa 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -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
@@ -9230,11 +9230,48 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
+ * 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();
}
}