Methods Summary |
---|
public void | addSpanWatchers(android.text.Spannable text)
final int textLength = text.length();
if (mKeyListener != null) {
text.setSpan(mKeyListener, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
if (mSpanController == null) {
mSpanController = new SpanController();
}
text.setSpan(mSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
void | adjustInputType(boolean password, boolean passwordInputType, boolean webPasswordInputType, boolean numberPasswordInputType)
// mInputType has been set from inputType, possibly modified by mInputMethod.
// Specialize mInputType to [web]password if we have a text class and the original input
// type was a password.
if ((mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) {
if (password || passwordInputType) {
mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION))
| EditorInfo.TYPE_TEXT_VARIATION_PASSWORD;
}
if (webPasswordInputType) {
mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION))
| EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
}
} else if ((mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_NUMBER) {
if (numberPasswordInputType) {
mInputType = (mInputType & ~(EditorInfo.TYPE_MASK_VARIATION))
| EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD;
}
}
|
boolean | areSuggestionsShown()
return mSuggestionsPopupWindow != null && mSuggestionsPopupWindow.isShowing();
|
public void | beginBatchEdit()
mInBatchEditControllers = true;
final InputMethodState ims = mInputMethodState;
if (ims != null) {
int nesting = ++ims.mBatchEditNesting;
if (nesting == 1) {
ims.mCursorChanged = false;
ims.mChangedDelta = 0;
if (ims.mContentChanged) {
// We already have a pending change from somewhere else,
// so turn this into a full update.
ims.mChangedStart = 0;
ims.mChangedEnd = mTextView.getText().length();
} else {
ims.mChangedStart = EXTRACT_UNKNOWN;
ims.mChangedEnd = EXTRACT_UNKNOWN;
ims.mContentChanged = false;
}
mTextView.onBeginBatchEdit();
}
}
|
private boolean | canSelectText()Unlike {@link TextView#textCanBeSelected()}, this method is based on the current state
of the TextView. textCanBeSelected() has to be true (this is one of the conditions to have
a selection controller (see {@link #prepareCursorControllers()}), but this is not sufficient.
return hasSelectionController() && mTextView.getText().length() != 0;
|
private void | chooseSize(PopupWindow pop, java.lang.CharSequence text, TextView tv)
int wid = tv.getPaddingLeft() + tv.getPaddingRight();
int ht = tv.getPaddingTop() + tv.getPaddingBottom();
int defaultWidthInPixels = mTextView.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.textview_error_popup_default_width);
Layout l = new StaticLayout(text, tv.getPaint(), defaultWidthInPixels,
Layout.Alignment.ALIGN_NORMAL, 1, 0, true);
float max = 0;
for (int i = 0; i < l.getLineCount(); i++) {
max = Math.max(max, l.getLineWidth(i));
}
/*
* Now set the popup size to be big enough for the text plus the border capped
* to DEFAULT_MAX_POPUP_WIDTH
*/
pop.setWidth(wid + (int) Math.ceil(max));
pop.setHeight(ht + l.getHeight());
|
void | createInputContentTypeIfNeeded()
if (mInputContentType == null) {
mInputContentType = new InputContentType();
}
|
void | createInputMethodStateIfNeeded()
if (mInputMethodState == null) {
mInputMethodState = new InputMethodState();
}
|
private void | destroyDisplayListsData()
if (mTextDisplayLists != null) {
for (int i = 0; i < mTextDisplayLists.length; i++) {
RenderNode displayList = mTextDisplayLists[i] != null
? mTextDisplayLists[i].displayList : null;
if (displayList != null && displayList.isValid()) {
displayList.destroyDisplayListData();
}
}
}
|
private void | downgradeEasyCorrectionSpans()Downgrades to simple suggestions all the easy correction spans that are not a spell check
span.
CharSequence text = mTextView.getText();
if (text instanceof Spannable) {
Spannable spannable = (Spannable) text;
SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
spannable.length(), SuggestionSpan.class);
for (int i = 0; i < suggestionSpans.length; i++) {
int flags = suggestionSpans[i].getFlags();
if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
&& (flags & SuggestionSpan.FLAG_MISSPELLED) == 0) {
flags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
suggestionSpans[i].setFlags(flags);
}
}
}
|
private void | drawCursor(android.graphics.Canvas canvas, int cursorOffsetVertical)
final boolean translate = cursorOffsetVertical != 0;
if (translate) canvas.translate(0, cursorOffsetVertical);
for (int i = 0; i < mCursorCount; i++) {
mCursorDrawable[i].draw(canvas);
}
if (translate) canvas.translate(0, -cursorOffsetVertical);
|
private void | drawHardwareAccelerated(android.graphics.Canvas canvas, android.text.Layout layout, android.graphics.Path highlight, android.graphics.Paint highlightPaint, int cursorOffsetVertical)
final long lineRange = layout.getLineRangeForDraw(canvas);
int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
if (lastLine < 0) return;
layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,
firstLine, lastLine);
if (layout instanceof DynamicLayout) {
if (mTextDisplayLists == null) {
mTextDisplayLists = ArrayUtils.emptyArray(TextDisplayList.class);
}
DynamicLayout dynamicLayout = (DynamicLayout) layout;
int[] blockEndLines = dynamicLayout.getBlockEndLines();
int[] blockIndices = dynamicLayout.getBlockIndices();
final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
final int indexFirstChangedBlock = dynamicLayout.getIndexFirstChangedBlock();
int endOfPreviousBlock = -1;
int searchStartIndex = 0;
for (int i = 0; i < numberOfBlocks; i++) {
int blockEndLine = blockEndLines[i];
int blockIndex = blockIndices[i];
final boolean blockIsInvalid = blockIndex == DynamicLayout.INVALID_BLOCK_INDEX;
if (blockIsInvalid) {
blockIndex = getAvailableDisplayListIndex(blockIndices, numberOfBlocks,
searchStartIndex);
// Note how dynamic layout's internal block indices get updated from Editor
blockIndices[i] = blockIndex;
searchStartIndex = blockIndex + 1;
}
if (mTextDisplayLists[blockIndex] == null) {
mTextDisplayLists[blockIndex] =
new TextDisplayList("Text " + blockIndex);
}
final boolean blockDisplayListIsInvalid = mTextDisplayLists[blockIndex].needsRecord();
RenderNode blockDisplayList = mTextDisplayLists[blockIndex].displayList;
if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) {
final int blockBeginLine = endOfPreviousBlock + 1;
final int top = layout.getLineTop(blockBeginLine);
final int bottom = layout.getLineBottom(blockEndLine);
int left = 0;
int right = mTextView.getWidth();
if (mTextView.getHorizontallyScrolling()) {
float min = Float.MAX_VALUE;
float max = Float.MIN_VALUE;
for (int line = blockBeginLine; line <= blockEndLine; line++) {
min = Math.min(min, layout.getLineLeft(line));
max = Math.max(max, layout.getLineRight(line));
}
left = (int) min;
right = (int) (max + 0.5f);
}
// Rebuild display list if it is invalid
if (blockDisplayListIsInvalid) {
final HardwareCanvas hardwareCanvas = blockDisplayList.start(
right - left, bottom - top);
try {
// drawText is always relative to TextView's origin, this translation
// brings this range of text back to the top left corner of the viewport
hardwareCanvas.translate(-left, -top);
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
// No need to untranslate, previous context is popped after
// drawDisplayList
} finally {
blockDisplayList.end(hardwareCanvas);
// Same as drawDisplayList below, handled by our TextView's parent
blockDisplayList.setClipToBounds(false);
}
}
// Valid disply list whose index is >= indexFirstChangedBlock
// only needs to update its drawing location.
blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
}
((HardwareCanvas) canvas).drawRenderNode(blockDisplayList, null,
0 /* no child clipping, our TextView parent enforces it */);
endOfPreviousBlock = blockEndLine;
}
dynamicLayout.setIndexFirstChangedBlock(numberOfBlocks);
} else {
// Boring layout is used for empty and hint text
layout.drawText(canvas, firstLine, lastLine);
}
|
public void | endBatchEdit()
mInBatchEditControllers = false;
final InputMethodState ims = mInputMethodState;
if (ims != null) {
int nesting = --ims.mBatchEditNesting;
if (nesting == 0) {
finishBatchEdit(ims);
}
}
|
void | ensureEndedBatchEdit()
final InputMethodState ims = mInputMethodState;
if (ims != null && ims.mBatchEditNesting != 0) {
ims.mBatchEditNesting = 0;
finishBatchEdit(ims);
}
|
boolean | extractText(android.view.inputmethod.ExtractedTextRequest request, android.view.inputmethod.ExtractedText outText)
return extractTextInternal(request, EXTRACT_UNKNOWN, EXTRACT_UNKNOWN,
EXTRACT_UNKNOWN, outText);
|
private boolean | extractTextInternal(android.view.inputmethod.ExtractedTextRequest request, int partialStartOffset, int partialEndOffset, int delta, android.view.inputmethod.ExtractedText outText)
final CharSequence content = mTextView.getText();
if (content != null) {
if (partialStartOffset != EXTRACT_NOTHING) {
final int N = content.length();
if (partialStartOffset < 0) {
outText.partialStartOffset = outText.partialEndOffset = -1;
partialStartOffset = 0;
partialEndOffset = N;
} else {
// Now use the delta to determine the actual amount of text
// we need.
partialEndOffset += delta;
// Adjust offsets to ensure we contain full spans.
if (content instanceof Spanned) {
Spanned spanned = (Spanned)content;
Object[] spans = spanned.getSpans(partialStartOffset,
partialEndOffset, ParcelableSpan.class);
int i = spans.length;
while (i > 0) {
i--;
int j = spanned.getSpanStart(spans[i]);
if (j < partialStartOffset) partialStartOffset = j;
j = spanned.getSpanEnd(spans[i]);
if (j > partialEndOffset) partialEndOffset = j;
}
}
outText.partialStartOffset = partialStartOffset;
outText.partialEndOffset = partialEndOffset - delta;
if (partialStartOffset > N) {
partialStartOffset = N;
} else if (partialStartOffset < 0) {
partialStartOffset = 0;
}
if (partialEndOffset > N) {
partialEndOffset = N;
} else if (partialEndOffset < 0) {
partialEndOffset = 0;
}
}
if ((request.flags&InputConnection.GET_TEXT_WITH_STYLES) != 0) {
outText.text = content.subSequence(partialStartOffset,
partialEndOffset);
} else {
outText.text = TextUtils.substring(content, partialStartOffset,
partialEndOffset);
}
} else {
outText.partialStartOffset = 0;
outText.partialEndOffset = 0;
outText.text = "";
}
outText.flags = 0;
if (MetaKeyKeyListener.getMetaState(content, MetaKeyKeyListener.META_SELECTING) != 0) {
outText.flags |= ExtractedText.FLAG_SELECTING;
}
if (mTextView.isSingleLine()) {
outText.flags |= ExtractedText.FLAG_SINGLE_LINE;
}
outText.startOffset = 0;
outText.selectionStart = mTextView.getSelectionStart();
outText.selectionEnd = mTextView.getSelectionEnd();
return true;
}
return false;
|
private boolean | extractedTextModeWillBeStarted()
if (!(mTextView instanceof ExtractEditText)) {
final InputMethodManager imm = InputMethodManager.peekInstance();
return imm != null && imm.isFullscreenMode();
}
return false;
|
void | finishBatchEdit(android.widget.Editor$InputMethodState ims)
mTextView.onEndBatchEdit();
if (ims.mContentChanged || ims.mSelectionModeChanged) {
mTextView.updateAfterEdit();
reportExtractedText();
} else if (ims.mCursorChanged) {
// Cheesy way to get us to report the current cursor location.
mTextView.invalidateCursor();
}
// sendUpdateSelection knows to avoid sending if the selection did
// not actually change.
sendUpdateSelection();
|
private int | getAvailableDisplayListIndex(int[] blockIndices, int numberOfBlocks, int searchStartIndex)
int length = mTextDisplayLists.length;
for (int i = searchStartIndex; i < length; i++) {
boolean blockIndexFound = false;
for (int j = 0; j < numberOfBlocks; j++) {
if (blockIndices[j] == i) {
blockIndexFound = true;
break;
}
}
if (blockIndexFound) continue;
return i;
}
// No available index found, the pool has to grow
mTextDisplayLists = GrowingArrayUtils.append(mTextDisplayLists, length, null);
return length;
|
private long | getCharRange(int offset)
final int textLength = mTextView.getText().length();
if (offset + 1 < textLength) {
final char currentChar = mTextView.getText().charAt(offset);
final char nextChar = mTextView.getText().charAt(offset + 1);
if (Character.isSurrogatePair(currentChar, nextChar)) {
return TextUtils.packRangeInLong(offset, offset + 2);
}
}
if (offset < textLength) {
return TextUtils.packRangeInLong(offset, offset + 1);
}
if (offset - 2 >= 0) {
final char previousChar = mTextView.getText().charAt(offset - 1);
final char previousPreviousChar = mTextView.getText().charAt(offset - 2);
if (Character.isSurrogatePair(previousPreviousChar, previousChar)) {
return TextUtils.packRangeInLong(offset - 2, offset);
}
}
if (offset - 1 >= 0) {
return TextUtils.packRangeInLong(offset - 1, offset);
}
return TextUtils.packRangeInLong(offset, offset);
|
private int | getErrorX()Returns the X offset to make the pointy top of the error point
at the middle of the error icon.
/*
* The "25" is the distance between the point and the right edge
* of the background
*/
final float scale = mTextView.getResources().getDisplayMetrics().density;
final Drawables dr = mTextView.mDrawables;
final int layoutDirection = mTextView.getLayoutDirection();
int errorX;
int offset;
switch (layoutDirection) {
default:
case View.LAYOUT_DIRECTION_LTR:
offset = - (dr != null ? dr.mDrawableSizeRight : 0) / 2 + (int) (25 * scale + 0.5f);
errorX = mTextView.getWidth() - mErrorPopup.getWidth() -
mTextView.getPaddingRight() + offset;
break;
case View.LAYOUT_DIRECTION_RTL:
offset = (dr != null ? dr.mDrawableSizeLeft : 0) / 2 - (int) (25 * scale + 0.5f);
errorX = mTextView.getPaddingLeft() + offset;
break;
}
return errorX;
|
private int | getErrorY()Returns the Y offset to make the pointy top of the error point
at the bottom of the error icon.
/*
* Compound, not extended, because the icon is not clipped
* if the text height is smaller.
*/
final int compoundPaddingTop = mTextView.getCompoundPaddingTop();
int vspace = mTextView.getBottom() - mTextView.getTop() -
mTextView.getCompoundPaddingBottom() - compoundPaddingTop;
final Drawables dr = mTextView.mDrawables;
final int layoutDirection = mTextView.getLayoutDirection();
int height;
switch (layoutDirection) {
default:
case View.LAYOUT_DIRECTION_LTR:
height = (dr != null ? dr.mDrawableHeightRight : 0);
break;
case View.LAYOUT_DIRECTION_RTL:
height = (dr != null ? dr.mDrawableHeightLeft : 0);
break;
}
int icontop = compoundPaddingTop + (vspace - height) / 2;
/*
* The "2" is the distance between the point and the top edge
* of the background.
*/
final float scale = mTextView.getResources().getDisplayMetrics().density;
return icontop + height - mTextView.getHeight() - (int) (2 * scale + 0.5f);
|
android.widget.Editor$InsertionPointCursorController | getInsertionController()
if (!mInsertionControllerEnabled) {
return null;
}
if (mInsertionPointCursorController == null) {
mInsertionPointCursorController = new InsertionPointCursorController();
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
}
return mInsertionPointCursorController;
|
private int | getLastTapPosition()
// No need to create the controller at that point, no last tap position saved
if (mSelectionModifierCursorController != null) {
int lastTapPosition = mSelectionModifierCursorController.getMinTouchOffset();
if (lastTapPosition >= 0) {
// Safety check, should not be possible.
if (lastTapPosition > mTextView.getText().length()) {
lastTapPosition = mTextView.getText().length();
}
return lastTapPosition;
}
}
return -1;
|
private long | getLastTouchOffsets()
SelectionModifierCursorController selectionController = getSelectionController();
final int minOffset = selectionController.getMinTouchOffset();
final int maxOffset = selectionController.getMaxTouchOffset();
return TextUtils.packRangeInLong(minOffset, maxOffset);
|
private android.widget.Editor$PositionListener | getPositionListener()
if (mPositionListener == null) {
mPositionListener = new PositionListener();
}
return mPositionListener;
|
private float | getPrimaryHorizontal(android.text.Layout layout, android.text.Layout hintLayout, int offset, boolean clamped)
if (TextUtils.isEmpty(layout.getText()) &&
hintLayout != null &&
!TextUtils.isEmpty(hintLayout.getText())) {
return hintLayout.getPrimaryHorizontal(offset, clamped);
} else {
return layout.getPrimaryHorizontal(offset, clamped);
}
|
android.widget.Editor$SelectionModifierCursorController | getSelectionController()
if (!mSelectionControllerEnabled) {
return null;
}
if (mSelectionModifierCursorController == null) {
mSelectionModifierCursorController = new SelectionModifierCursorController();
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
return mSelectionModifierCursorController;
|
private android.view.View.DragShadowBuilder | getTextThumbnailBuilder(java.lang.CharSequence text)
TextView shadowView = (TextView) View.inflate(mTextView.getContext(),
com.android.internal.R.layout.text_drag_thumbnail, null);
if (shadowView == null) {
throw new IllegalArgumentException("Unable to inflate text drag thumbnail");
}
if (text.length() > DRAG_SHADOW_MAX_TEXT_LENGTH) {
text = text.subSequence(0, DRAG_SHADOW_MAX_TEXT_LENGTH);
}
shadowView.setText(text);
shadowView.setTextColor(mTextView.getTextColors());
shadowView.setTextAppearance(mTextView.getContext(), R.styleable.Theme_textAppearanceLarge);
shadowView.setGravity(Gravity.CENTER);
shadowView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
final int size = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
shadowView.measure(size, size);
shadowView.layout(0, 0, shadowView.getMeasuredWidth(), shadowView.getMeasuredHeight());
shadowView.invalidate();
return new DragShadowBuilder(shadowView);
|
public android.text.method.WordIterator | getWordIterator()
if (mWordIterator == null) {
mWordIterator = new WordIterator(mTextView.getTextServicesLocale());
}
return mWordIterator;
|
boolean | hasInsertionController()
return mInsertionControllerEnabled;
|
private boolean | hasPasswordTransformationMethod()It would be better to rely on the input type for everything. A password inputType should have
a password transformation. We should hence use isPasswordInputType instead of this method.
We should:
- Call setInputType in setKeyListener instead of changing the input type directly (which
would install the correct transformation).
- Refuse the installation of a non-password transformation in setTransformation if the input
type is password.
However, this is like this for legacy reasons and we cannot break existing apps. This method
is useful since it matches what the user can see (obfuscated text or not).
return mTextView.getTransformationMethod() instanceof PasswordTransformationMethod;
|
boolean | hasSelectionController()
return mSelectionControllerEnabled;
|
void | hideControllers()Hides the insertion controller and stops text selection mode, hiding the selection controller
hideCursorControllers();
hideSpanControllers();
|
private void | hideCursorControllers()
if (mSuggestionsPopupWindow != null && !mSuggestionsPopupWindow.isShowingUp()) {
// Should be done before hide insertion point controller since it triggers a show of it
mSuggestionsPopupWindow.hide();
}
hideInsertionPointCursorController();
stopSelectionActionMode();
|
private void | hideError()
if (mErrorPopup != null) {
if (mErrorPopup.isShowing()) {
mErrorPopup.dismiss();
}
}
mShowErrorAfterAttach = false;
|
private void | hideInsertionPointCursorController()
if (mInsertionPointCursorController != null) {
mInsertionPointCursorController.hide();
}
|
private void | hideSpanControllers()
if (mSpanController != null) {
mSpanController.hide();
}
|
void | invalidateTextDisplayList(android.text.Layout layout, int start, int end)Invalidates all the sub-display lists that overlap the specified character range
if (mTextDisplayLists != null && layout instanceof DynamicLayout) {
final int firstLine = layout.getLineForOffset(start);
final int lastLine = layout.getLineForOffset(end);
DynamicLayout dynamicLayout = (DynamicLayout) layout;
int[] blockEndLines = dynamicLayout.getBlockEndLines();
int[] blockIndices = dynamicLayout.getBlockIndices();
final int numberOfBlocks = dynamicLayout.getNumberOfBlocks();
int i = 0;
// Skip the blocks before firstLine
while (i < numberOfBlocks) {
if (blockEndLines[i] >= firstLine) break;
i++;
}
// Invalidate all subsequent blocks until lastLine is passed
while (i < numberOfBlocks) {
final int blockIndex = blockIndices[i];
if (blockIndex != DynamicLayout.INVALID_BLOCK_INDEX) {
mTextDisplayLists[blockIndex].isDirty = true;
}
if (blockEndLines[i] >= lastLine) break;
i++;
}
}
|
void | invalidateTextDisplayList()
if (mTextDisplayLists != null) {
for (int i = 0; i < mTextDisplayLists.length; i++) {
if (mTextDisplayLists[i] != null) mTextDisplayLists[i].isDirty = true;
}
}
|
private boolean | isCursorInsideEasyCorrectionSpan()
Spannable spannable = (Spannable) mTextView.getText();
SuggestionSpan[] suggestionSpans = spannable.getSpans(mTextView.getSelectionStart(),
mTextView.getSelectionEnd(), SuggestionSpan.class);
for (int i = 0; i < suggestionSpans.length; i++) {
if ((suggestionSpans[i].getFlags() & SuggestionSpan.FLAG_EASY_CORRECT) != 0) {
return true;
}
}
return false;
|
private boolean | isCursorInsideSuggestionSpan()
CharSequence text = mTextView.getText();
if (!(text instanceof Spannable)) return false;
SuggestionSpan[] suggestionSpans = ((Spannable) text).getSpans(
mTextView.getSelectionStart(), mTextView.getSelectionEnd(), SuggestionSpan.class);
return (suggestionSpans.length > 0);
|
boolean | isCursorVisible()
// The default value is true, even when there is no associated Editor
return mCursorVisible && mTextView.isTextEditable();
|
private boolean | isOffsetVisible(int offset)
Layout layout = mTextView.getLayout();
if (layout == null) return false;
final int line = layout.getLineForOffset(offset);
final int lineBottom = layout.getLineBottom(line);
final int primaryHorizontal = (int) layout.getPrimaryHorizontal(offset);
return isPositionVisible(primaryHorizontal + mTextView.viewportToContentHorizontalOffset(),
lineBottom + mTextView.viewportToContentVerticalOffset());
|
private boolean | isPositionOnText(float x, float y)Returns true if the screen coordinates position (x,y) corresponds to a character displayed
in the view. Returns false when the position is in the empty space of left/right of text.
Layout layout = mTextView.getLayout();
if (layout == null) return false;
final int line = mTextView.getLineAtCoordinate(y);
x = mTextView.convertToLocalHorizontalCoordinate(x);
if (x < layout.getLineLeft(line)) return false;
if (x > layout.getLineRight(line)) return false;
return true;
|
private boolean | isPositionVisible(float positionX, float positionY)
synchronized (TEMP_POSITION) {
final float[] position = TEMP_POSITION;
position[0] = positionX;
position[1] = positionY;
View view = mTextView;
while (view != null) {
if (view != mTextView) {
// Local scroll is already taken into account in positionX/Y
position[0] -= view.getScrollX();
position[1] -= view.getScrollY();
}
if (position[0] < 0 || position[1] < 0 ||
position[0] > view.getWidth() || position[1] > view.getHeight()) {
return false;
}
if (!view.getMatrix().isIdentity()) {
view.getMatrix().mapPoints(position);
}
position[0] += view.getLeft();
position[1] += view.getTop();
final ViewParent parent = view.getParent();
if (parent instanceof View) {
view = (View) parent;
} else {
// We've reached the ViewRoot, stop iterating
view = null;
}
}
}
// We've been able to walk up the view hierarchy and the position was never clipped
return true;
|
void | makeBlink()
if (shouldBlink()) {
mShowCursor = SystemClock.uptimeMillis();
if (mBlink == null) mBlink = new Blink();
mBlink.removeCallbacks(mBlink);
mBlink.postAtTime(mBlink, mShowCursor + BLINK);
} else {
if (mBlink != null) mBlink.removeCallbacks(mBlink);
}
|
void | onAttachedToWindow()
if (mShowErrorAfterAttach) {
showError();
mShowErrorAfterAttach = false;
}
mTemporaryDetach = false;
final ViewTreeObserver observer = mTextView.getViewTreeObserver();
// No need to create the controller.
// The get method will add the listener on controller creation.
if (mInsertionPointCursorController != null) {
observer.addOnTouchModeChangeListener(mInsertionPointCursorController);
}
if (mSelectionModifierCursorController != null) {
mSelectionModifierCursorController.resetTouchOffsets();
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
updateSpellCheckSpans(0, mTextView.getText().length(),
true /* create the spell checker if needed */);
if (mTextView.hasTransientState() &&
mTextView.getSelectionStart() != mTextView.getSelectionEnd()) {
// Since transient state is reference counted make sure it stays matched
// with our own calls to it for managing selection.
// The action mode callback will set this back again when/if the action mode starts.
mTextView.setHasTransientState(false);
// We had an active selection from before, start the selection mode.
startSelectionActionMode();
}
getPositionListener().addSubscriber(mCursorAnchorInfoNotifier, true);
|
public void | onCommitCorrection(android.view.inputmethod.CorrectionInfo info)Called by the framework in response to a text auto-correction (such as fixing a typo using a
a dictionnary) from the current input method, provided by it calling
{@link InputConnection#commitCorrection} InputConnection.commitCorrection()}. The default
implementation flashes the background of the corrected word to provide feedback to the user.
if (mCorrectionHighlighter == null) {
mCorrectionHighlighter = new CorrectionHighlighter();
} else {
mCorrectionHighlighter.invalidate(false);
}
mCorrectionHighlighter.highlight(info);
|
void | onDetachedFromWindow()
getPositionListener().removeSubscriber(mCursorAnchorInfoNotifier);
if (mError != null) {
hideError();
}
if (mBlink != null) {
mBlink.removeCallbacks(mBlink);
}
if (mInsertionPointCursorController != null) {
mInsertionPointCursorController.onDetached();
}
if (mSelectionModifierCursorController != null) {
mSelectionModifierCursorController.onDetached();
}
if (mShowSuggestionRunnable != null) {
mTextView.removeCallbacks(mShowSuggestionRunnable);
}
destroyDisplayListsData();
if (mSpellChecker != null) {
mSpellChecker.closeSession();
// Forces the creation of a new SpellChecker next time this window is created.
// Will handle the cases where the settings has been changed in the meantime.
mSpellChecker = null;
}
mPreserveDetachedSelection = true;
hideControllers();
mPreserveDetachedSelection = false;
mTemporaryDetach = false;
|
void | onDraw(android.graphics.Canvas canvas, android.text.Layout layout, android.graphics.Path highlight, android.graphics.Paint highlightPaint, int cursorOffsetVertical)
final int selectionStart = mTextView.getSelectionStart();
final int selectionEnd = mTextView.getSelectionEnd();
final InputMethodState ims = mInputMethodState;
if (ims != null && ims.mBatchEditNesting == 0) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
if (imm.isActive(mTextView)) {
boolean reported = false;
if (ims.mContentChanged || ims.mSelectionModeChanged) {
// We are in extract mode and the content has changed
// in some way... just report complete new text to the
// input method.
reported = reportExtractedText();
}
}
}
}
if (mCorrectionHighlighter != null) {
mCorrectionHighlighter.draw(canvas, cursorOffsetVertical);
}
if (highlight != null && selectionStart == selectionEnd && mCursorCount > 0) {
drawCursor(canvas, cursorOffsetVertical);
// Rely on the drawable entirely, do not draw the cursor line.
// Has to be done after the IMM related code above which relies on the highlight.
highlight = null;
}
if (mTextView.canHaveDisplayList() && canvas.isHardwareAccelerated()) {
drawHardwareAccelerated(canvas, layout, highlight, highlightPaint,
cursorOffsetVertical);
} else {
layout.draw(canvas, highlight, highlightPaint, cursorOffsetVertical);
}
|
void | onDrop(android.view.DragEvent event)
StringBuilder content = new StringBuilder("");
ClipData clipData = event.getClipData();
final int itemCount = clipData.getItemCount();
for (int i=0; i < itemCount; i++) {
Item item = clipData.getItemAt(i);
content.append(item.coerceToStyledText(mTextView.getContext()));
}
final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
Object localState = event.getLocalState();
DragLocalState dragLocalState = null;
if (localState instanceof DragLocalState) {
dragLocalState = (DragLocalState) localState;
}
boolean dragDropIntoItself = dragLocalState != null &&
dragLocalState.sourceTextView == mTextView;
if (dragDropIntoItself) {
if (offset >= dragLocalState.start && offset < dragLocalState.end) {
// A drop inside the original selection discards the drop.
return;
}
}
final int originalLength = mTextView.getText().length();
int min = offset;
int max = offset;
Selection.setSelection((Spannable) mTextView.getText(), max);
mTextView.replaceText_internal(min, max, content);
if (dragDropIntoItself) {
int dragSourceStart = dragLocalState.start;
int dragSourceEnd = dragLocalState.end;
if (max <= dragSourceStart) {
// Inserting text before selection has shifted positions
final int shift = mTextView.getText().length() - originalLength;
dragSourceStart += shift;
dragSourceEnd += shift;
}
// Delete original selection
mTextView.deleteText_internal(dragSourceStart, dragSourceEnd);
// Make sure we do not leave two adjacent spaces.
final int prevCharIdx = Math.max(0, dragSourceStart - 1);
final int nextCharIdx = Math.min(mTextView.getText().length(), dragSourceStart + 1);
if (nextCharIdx > prevCharIdx + 1) {
CharSequence t = mTextView.getTransformedText(prevCharIdx, nextCharIdx);
if (Character.isSpaceChar(t.charAt(0)) && Character.isSpaceChar(t.charAt(1))) {
mTextView.deleteText_internal(prevCharIdx, prevCharIdx + 1);
}
}
}
|
void | onFocusChanged(boolean focused, int direction)
mShowCursor = SystemClock.uptimeMillis();
ensureEndedBatchEdit();
if (focused) {
int selStart = mTextView.getSelectionStart();
int selEnd = mTextView.getSelectionEnd();
// SelectAllOnFocus fields are highlighted and not selected. Do not start text selection
// mode for these, unless there was a specific selection already started.
final boolean isFocusHighlighted = mSelectAllOnFocus && selStart == 0 &&
selEnd == mTextView.getText().length();
mCreatedWithASelection = mFrozenWithFocus && mTextView.hasSelection() &&
!isFocusHighlighted;
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.
final int lastTapPosition = getLastTapPosition();
if (lastTapPosition >= 0) {
Selection.setSelection((Spannable) mTextView.getText(), lastTapPosition);
}
// Note this may have to be moved out of the Editor class
MovementMethod mMovement = mTextView.getMovementMethod();
if (mMovement != null) {
mMovement.onTakeFocus(mTextView, (Spannable) mTextView.getText(), direction);
}
// The DecorView does not have focus when the 'Done' ExtractEditText button is
// pressed. Since it is the ViewAncestor's mView, it requests focus before
// ExtractEditText clears focus, which gives focus to the ExtractEditText.
// This special case ensure that we keep current selection in that case.
// It would be better to know why the DecorView does not have focus at that time.
if (((mTextView instanceof ExtractEditText) || mSelectionMoved) &&
selStart >= 0 && selEnd >= 0) {
/*
* Someone intentionally set the selection, so let them
* do whatever it is that they wanted to do instead of
* the default on-focus behavior. We reset the selection
* here instead of just skipping the onTakeFocus() call
* because some movement methods do something other than
* just setting the selection in theirs and we still
* need to go through that path.
*/
Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
}
if (mSelectAllOnFocus) {
mTextView.selectAllText();
}
mTouchFocusSelected = true;
}
mFrozenWithFocus = false;
mSelectionMoved = false;
if (mError != null) {
showError();
}
makeBlink();
} else {
if (mError != null) {
hideError();
}
// Don't leave us in the middle of a batch edit.
mTextView.onEndBatchEdit();
if (mTextView instanceof ExtractEditText) {
// terminateTextSelectionMode removes selection, which we want to keep when
// ExtractEditText goes out of focus.
final int selStart = mTextView.getSelectionStart();
final int selEnd = mTextView.getSelectionEnd();
hideControllers();
Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
} else {
if (mTemporaryDetach) mPreserveDetachedSelection = true;
hideControllers();
if (mTemporaryDetach) mPreserveDetachedSelection = false;
downgradeEasyCorrectionSpans();
}
// No need to create the controller
if (mSelectionModifierCursorController != null) {
mSelectionModifierCursorController.resetTouchOffsets();
}
}
|
void | onLocaleChanged()
// Will be re-created on demand in getWordIterator with the proper new locale
mWordIterator = null;
|
void | onScreenStateChanged(int screenState)
switch (screenState) {
case View.SCREEN_STATE_ON:
resumeBlink();
break;
case View.SCREEN_STATE_OFF:
suspendBlink();
break;
}
|
void | onScrollChanged()
if (mPositionListener != null) {
mPositionListener.onScrollChanged();
}
|
void | onTouchEvent(android.view.MotionEvent event)
if (hasSelectionController()) {
getSelectionController().onTouchEvent(event);
}
if (mShowSuggestionRunnable != null) {
mTextView.removeCallbacks(mShowSuggestionRunnable);
mShowSuggestionRunnable = null;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mLastDownPositionX = event.getX();
mLastDownPositionY = event.getY();
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
mTouchFocusSelected = false;
mIgnoreActionUpEvent = false;
}
|
void | onTouchUpEvent(android.view.MotionEvent event)
boolean selectAllGotFocus = mSelectAllOnFocus && mTextView.didTouchFocusSelect();
hideControllers();
CharSequence text = mTextView.getText();
if (!selectAllGotFocus && text.length() > 0) {
// Move cursor
final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
Selection.setSelection((Spannable) text, offset);
if (mSpellChecker != null) {
// When the cursor moves, the word that was typed may need spell check
mSpellChecker.onSelectionChanged();
}
if (!extractedTextModeWillBeStarted()) {
if (isCursorInsideEasyCorrectionSpan()) {
mShowSuggestionRunnable = new Runnable() {
public void run() {
showSuggestions();
}
};
// removeCallbacks is performed on every touch
mTextView.postDelayed(mShowSuggestionRunnable,
ViewConfiguration.getDoubleTapTimeout());
} else if (hasInsertionController()) {
getInsertionController().show();
}
}
}
|
void | onWindowFocusChanged(boolean hasWindowFocus)
if (hasWindowFocus) {
if (mBlink != null) {
mBlink.uncancel();
makeBlink();
}
} else {
if (mBlink != null) {
mBlink.cancel();
}
if (mInputContentType != null) {
mInputContentType.enterDown = false;
}
// Order matters! Must be done before onParentLostFocus to rely on isShowingUp
hideControllers();
if (mSuggestionsPopupWindow != null) {
mSuggestionsPopupWindow.onParentLostFocus();
}
// Don't leave us in the middle of a batch edit. Same as in onFocusChanged
ensureEndedBatchEdit();
}
|
public boolean | performLongClick(boolean handled)
// Long press in empty space moves cursor and shows the Paste affordance if available.
if (!handled && !isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
mInsertionControllerEnabled) {
final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
mLastDownPositionY);
stopSelectionActionMode();
Selection.setSelection((Spannable) mTextView.getText(), offset);
getInsertionController().showWithActionPopup();
handled = true;
}
if (!handled && mSelectionActionMode != null) {
if (touchPositionIsInSelection()) {
// Start a drag
final int start = mTextView.getSelectionStart();
final int end = mTextView.getSelectionEnd();
CharSequence selectedText = mTextView.getTransformedText(start, end);
ClipData data = ClipData.newPlainText(null, selectedText);
DragLocalState localState = new DragLocalState(mTextView, start, end);
mTextView.startDrag(data, getTextThumbnailBuilder(selectedText), localState, 0);
stopSelectionActionMode();
} else {
getSelectionController().hide();
selectCurrentWord();
getSelectionController().show();
}
handled = true;
}
// Start a new selection
if (!handled) {
handled = startSelectionActionMode();
}
return handled;
|
void | prepareCursorControllers()
boolean windowSupportsHandles = false;
ViewGroup.LayoutParams params = mTextView.getRootView().getLayoutParams();
if (params instanceof WindowManager.LayoutParams) {
WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
windowSupportsHandles = windowParams.type < WindowManager.LayoutParams.FIRST_SUB_WINDOW
|| windowParams.type > WindowManager.LayoutParams.LAST_SUB_WINDOW;
}
boolean enabled = windowSupportsHandles && mTextView.getLayout() != null;
mInsertionControllerEnabled = enabled && isCursorVisible();
mSelectionControllerEnabled = enabled && mTextView.textCanBeSelected();
if (!mInsertionControllerEnabled) {
hideInsertionPointCursorController();
if (mInsertionPointCursorController != null) {
mInsertionPointCursorController.onDetached();
mInsertionPointCursorController = null;
}
}
if (!mSelectionControllerEnabled) {
stopSelectionActionMode();
if (mSelectionModifierCursorController != null) {
mSelectionModifierCursorController.onDetached();
mSelectionModifierCursorController = null;
}
}
|
boolean | reportExtractedText()
final Editor.InputMethodState ims = mInputMethodState;
if (ims != null) {
final boolean contentChanged = ims.mContentChanged;
if (contentChanged || ims.mSelectionModeChanged) {
ims.mContentChanged = false;
ims.mSelectionModeChanged = false;
final ExtractedTextRequest req = ims.mExtractedTextRequest;
if (req != null) {
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
if (TextView.DEBUG_EXTRACT) Log.v(TextView.LOG_TAG,
"Retrieving extracted start=" + ims.mChangedStart +
" end=" + ims.mChangedEnd +
" delta=" + ims.mChangedDelta);
if (ims.mChangedStart < 0 && !contentChanged) {
ims.mChangedStart = EXTRACT_NOTHING;
}
if (extractTextInternal(req, ims.mChangedStart, ims.mChangedEnd,
ims.mChangedDelta, ims.mExtractedText)) {
if (TextView.DEBUG_EXTRACT) Log.v(TextView.LOG_TAG,
"Reporting extracted start=" +
ims.mExtractedText.partialStartOffset +
" end=" + ims.mExtractedText.partialEndOffset +
": " + ims.mExtractedText.text);
imm.updateExtractedText(mTextView, req.token, ims.mExtractedText);
ims.mChangedStart = EXTRACT_UNKNOWN;
ims.mChangedEnd = EXTRACT_UNKNOWN;
ims.mChangedDelta = 0;
ims.mContentChanged = false;
return true;
}
}
}
}
}
return false;
|
private void | resumeBlink()
if (mBlink != null) {
mBlink.uncancel();
makeBlink();
}
|
private boolean | selectCurrentWord()Adjusts selection to the word under last touch offset.
Return true if the operation was successfully performed.
if (!canSelectText()) {
return false;
}
if (hasPasswordTransformationMethod()) {
// Always select all on a password field.
// Cut/copy menu entries are not available for passwords, but being able to select all
// is however useful to delete or paste to replace the entire content.
return mTextView.selectAllText();
}
int inputType = mTextView.getInputType();
int klass = inputType & InputType.TYPE_MASK_CLASS;
int variation = inputType & InputType.TYPE_MASK_VARIATION;
// Specific text field types: select the entire text for these
if (klass == InputType.TYPE_CLASS_NUMBER ||
klass == InputType.TYPE_CLASS_PHONE ||
klass == InputType.TYPE_CLASS_DATETIME ||
variation == InputType.TYPE_TEXT_VARIATION_URI ||
variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ||
variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
return mTextView.selectAllText();
}
long lastTouchOffsets = getLastTouchOffsets();
final int minOffset = TextUtils.unpackRangeStartFromLong(lastTouchOffsets);
final int maxOffset = TextUtils.unpackRangeEndFromLong(lastTouchOffsets);
// Safety check in case standard touch event handling has been bypassed
if (minOffset < 0 || minOffset >= mTextView.getText().length()) return false;
if (maxOffset < 0 || maxOffset >= mTextView.getText().length()) return false;
int selectionStart, selectionEnd;
// If a URLSpan (web address, email, phone...) is found at that position, select it.
URLSpan[] urlSpans = ((Spanned) mTextView.getText()).
getSpans(minOffset, maxOffset, URLSpan.class);
if (urlSpans.length >= 1) {
URLSpan urlSpan = urlSpans[0];
selectionStart = ((Spanned) mTextView.getText()).getSpanStart(urlSpan);
selectionEnd = ((Spanned) mTextView.getText()).getSpanEnd(urlSpan);
} else {
final WordIterator wordIterator = getWordIterator();
wordIterator.setCharSequence(mTextView.getText(), minOffset, maxOffset);
selectionStart = wordIterator.getBeginning(minOffset);
selectionEnd = wordIterator.getEnd(maxOffset);
if (selectionStart == BreakIterator.DONE || selectionEnd == BreakIterator.DONE ||
selectionStart == selectionEnd) {
// Possible when the word iterator does not properly handle the text's language
long range = getCharRange(minOffset);
selectionStart = TextUtils.unpackRangeStartFromLong(range);
selectionEnd = TextUtils.unpackRangeEndFromLong(range);
}
}
Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
return selectionEnd > selectionStart;
|
void | sendOnTextChanged(int start, int after)
updateSpellCheckSpans(start, start + after, false);
// Hide the controllers as soon as text is modified (typing, procedural...)
// 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();
|
private void | sendUpdateSelection()
if (null != mInputMethodState && mInputMethodState.mBatchEditNesting <= 0) {
final InputMethodManager imm = InputMethodManager.peekInstance();
if (null != imm) {
final int selectionStart = mTextView.getSelectionStart();
final int selectionEnd = mTextView.getSelectionEnd();
int candStart = -1;
int candEnd = -1;
if (mTextView.getText() instanceof Spannable) {
final Spannable sp = (Spannable) mTextView.getText();
candStart = EditableInputConnection.getComposingSpanStart(sp);
candEnd = EditableInputConnection.getComposingSpanEnd(sp);
}
// InputMethodManager#updateSelection skips sending the message if
// none of the parameters have changed since the last time we called it.
imm.updateSelection(mTextView,
selectionStart, selectionEnd, candStart, candEnd);
}
}
|
public void | setError(java.lang.CharSequence error, android.graphics.drawable.Drawable icon)
mError = TextUtils.stringOrSpannedString(error);
mErrorWasChanged = true;
if (mError == null) {
setErrorIcon(null);
if (mErrorPopup != null) {
if (mErrorPopup.isShowing()) {
mErrorPopup.dismiss();
}
mErrorPopup = null;
}
mShowErrorAfterAttach = false;
} else {
setErrorIcon(icon);
if (mTextView.isFocused()) {
showError();
}
}
|
private void | setErrorIcon(android.graphics.drawable.Drawable icon)
Drawables dr = mTextView.mDrawables;
if (dr == null) {
mTextView.mDrawables = dr = new Drawables(mTextView.getContext());
}
dr.setErrorDrawable(icon, mTextView);
mTextView.resetResolvedDrawables();
mTextView.invalidate();
mTextView.requestLayout();
|
void | setFrame()
if (mErrorPopup != null) {
TextView tv = (TextView) mErrorPopup.getContentView();
chooseSize(mErrorPopup, mError, tv);
mErrorPopup.update(mTextView, getErrorX(), getErrorY(),
mErrorPopup.getWidth(), mErrorPopup.getHeight());
}
|
private boolean | shouldBlink()
if (!isCursorVisible() || !mTextView.isFocused()) return false;
final int start = mTextView.getSelectionStart();
if (start < 0) return false;
final int end = mTextView.getSelectionEnd();
if (end < 0) return false;
return start == end;
|
private void | showError()
if (mTextView.getWindowToken() == null) {
mShowErrorAfterAttach = true;
return;
}
if (mErrorPopup == null) {
LayoutInflater inflater = LayoutInflater.from(mTextView.getContext());
final TextView err = (TextView) inflater.inflate(
com.android.internal.R.layout.textview_hint, null);
final float scale = mTextView.getResources().getDisplayMetrics().density;
mErrorPopup = new ErrorPopup(err, (int)(200 * scale + 0.5f), (int)(50 * scale + 0.5f));
mErrorPopup.setFocusable(false);
// The user is entering text, so the input method is needed. We
// don't want the popup to be displayed on top of it.
mErrorPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
}
TextView tv = (TextView) mErrorPopup.getContentView();
chooseSize(mErrorPopup, mError, tv);
tv.setText(mError);
mErrorPopup.showAsDropDown(mTextView, getErrorX(), getErrorY());
mErrorPopup.fixDirection(mErrorPopup.isAboveAnchor());
|
void | showSuggestions()
if (mSuggestionsPopupWindow == null) {
mSuggestionsPopupWindow = new SuggestionsPopupWindow();
}
hideControllers();
mSuggestionsPopupWindow.show();
|
boolean | startSelectionActionMode()
if (mSelectionActionMode != null) {
// Selection action mode is already started
return false;
}
if (!canSelectText() || !mTextView.requestFocus()) {
Log.w(TextView.LOG_TAG,
"TextView does not support text selection. Action mode cancelled.");
return false;
}
if (!mTextView.hasSelection()) {
// There may already be a selection on device rotation
if (!selectCurrentWord()) {
// No word found under cursor or text selection not permitted.
return false;
}
}
boolean willExtract = extractedTextModeWillBeStarted();
// 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(actionModeCallback);
}
final boolean selectionStarted = mSelectionActionMode != 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();
if (imm != null) {
imm.showSoftInput(mTextView, 0, null);
}
}
return selectionStarted;
|
protected void | stopSelectionActionMode()
if (mSelectionActionMode != null) {
// This will hide the mSelectionModifierCursorController
mSelectionActionMode.finish();
}
|
private void | suspendBlink()
if (mBlink != null) {
mBlink.cancel();
}
|
private boolean | touchPositionIsInSelection()
int selectionStart = mTextView.getSelectionStart();
int selectionEnd = mTextView.getSelectionEnd();
if (selectionStart == selectionEnd) {
return false;
}
if (selectionStart > selectionEnd) {
int tmp = selectionStart;
selectionStart = selectionEnd;
selectionEnd = tmp;
Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
}
SelectionModifierCursorController selectionController = getSelectionController();
int minOffset = selectionController.getMinTouchOffset();
int maxOffset = selectionController.getMaxTouchOffset();
return ((minOffset >= selectionStart) && (maxOffset < selectionEnd));
|
private void | updateCursorPosition(int cursorIndex, int top, int bottom, float horizontal)
if (mCursorDrawable[cursorIndex] == null)
mCursorDrawable[cursorIndex] = mTextView.getContext().getDrawable(
mTextView.mCursorDrawableRes);
if (mTempRect == null) mTempRect = new Rect();
mCursorDrawable[cursorIndex].getPadding(mTempRect);
final int width = mCursorDrawable[cursorIndex].getIntrinsicWidth();
horizontal = Math.max(0.5f, horizontal - 0.5f);
final int left = (int) (horizontal) - mTempRect.left;
mCursorDrawable[cursorIndex].setBounds(left, top - mTempRect.top, left + width,
bottom + mTempRect.bottom);
|
void | updateCursorsPositions()
if (mTextView.mCursorDrawableRes == 0) {
mCursorCount = 0;
return;
}
Layout layout = mTextView.getLayout();
Layout hintLayout = mTextView.getHintLayout();
final int offset = mTextView.getSelectionStart();
final int line = layout.getLineForOffset(offset);
final int top = layout.getLineTop(line);
final int bottom = layout.getLineTop(line + 1);
mCursorCount = layout.isLevelBoundary(offset) ? 2 : 1;
int middle = bottom;
if (mCursorCount == 2) {
// Similar to what is done in {@link Layout.#getCursorPath(int, Path, CharSequence)}
middle = (top + bottom) >> 1;
}
boolean clamped = layout.shouldClampCursor(line);
updateCursorPosition(0, top, middle,
getPrimaryHorizontal(layout, hintLayout, offset, clamped));
if (mCursorCount == 2) {
updateCursorPosition(1, middle, bottom,
layout.getSecondaryHorizontal(offset, clamped));
}
|
private void | updateSpellCheckSpans(int start, int end, boolean createSpellChecker)Create new SpellCheckSpans on the modified region.
// Remove spans whose adjacent characters are text not punctuation
mTextView.removeAdjacentSuggestionSpans(start);
mTextView.removeAdjacentSuggestionSpans(end);
if (mTextView.isTextEditable() && mTextView.isSuggestionsEnabled() &&
!(mTextView instanceof ExtractEditText)) {
if (mSpellChecker == null && createSpellChecker) {
mSpellChecker = new SpellChecker(mTextView);
}
if (mSpellChecker != null) {
mSpellChecker.spellCheck(start, end);
}
}
|