/**
* @param event
/**
*/
@Override
}
}
if (clip != null) {
clipboard.setPrimaryClip(clip);
}
}
}
}
// Two ints packed in a long
return packRangeInLong(start, end);
}
private static long packRangeInLong(int start, int end) {
return (((long) start) << 32) | end;
}
private static int extractRangeStartFromLong(long range) {
return (int) (range >>> 32);
}
private static int extractRangeEndFromLong(long range) {
return (int) (range & 0x00000000FFFFFFFFL);
}
private void selectCurrentWord() {
// In case selection mode is started after an orientation change or after a select all,
// use the current selection instead of creating one
if (hasSelection()) {
return;
}
int minOffset, maxOffset;
if (mDPadCenterIsDown || mEnterKeyIsDown) {
minOffset = getSelectionStart();
maxOffset = getSelectionEnd();
} else {
// selectionModifierCursorController is not null at that point
SelectionModifierCursorController selectionModifierCursorController =
((SelectionModifierCursorController) mSelectionModifierCursorController);
minOffset = selectionModifierCursorController.getMinTouchOffset();
maxOffset = selectionModifierCursorController.getMaxTouchOffset();
}
int selectionStart, selectionEnd;
long wordLimits = getWordLimitsAt(minOffset);
if (wordLimits >= 0) {
selectionStart = extractRangeStartFromLong(wordLimits);
} else {
selectionStart = Math.max(minOffset - 5, 0);
}
wordLimits = getWordLimitsAt(maxOffset);
if (wordLimits >= 0) {
selectionEnd = extractRangeEndFromLong(wordLimits);
} else {
selectionEnd = Math.min(maxOffset + 5, mText.length());
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
if (!isShown()) {
return false;
}
final boolean isPassword = isPasswordInputType(mInputType);
if (!isPassword) {
CharSequence text = getText();
if (TextUtils.isEmpty(text)) {
text = getHint();
}
if (!TextUtils.isEmpty(text)) {
if (text.length() > AccessibilityEvent.MAX_TEXT_LENGTH) {
text = text.subSequence(0, AccessibilityEvent.MAX_TEXT_LENGTH + 1);
}
event.getText().add(text);
}
} else {
event.setPassword(isPassword);
}
return false;
}
void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
int fromIndex, int removedCount, int addedCount) {
AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
event.setFromIndex(fromIndex);
event.setRemovedCount(removedCount);
event.setAddedCount(addedCount);
event.setBeforeText(beforeText);
sendAccessibilityEventUnchecked(event);
}
protected void onCreateContextMenu(ContextMenu menu) {
super.onCreateContextMenu(menu);
boolean added = false;
MenuHandler handler = new MenuHandler();
if (mText instanceof Spanned) {
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
URLSpan[] urls = ((Spanned) mText).getSpans(min, max,
URLSpan.class);
if (urls.length == 1) {
menu.add(0, ID_COPY_URL, 0,
com.android.internal.R.string.copyUrl).
setOnMenuItemClickListener(handler);
added = true;
}
}
// The context menu is not empty, which will prevent the selection mode from starting.
// Add a entry to start it in the context menu.
// TODO Does not handle the case where a subclass does not call super.thisMethod or
// populates the menu AFTER this call.
if (menu.size() > 0) {
menu.add(0, ID_SELECTION_MODE, 0, com.android.internal.R.string.selectTextMode).
setOnMenuItemClickListener(handler);
added = true;
}
if (added) {
menu.setHeaderTitle(com.android.internal.R.string.editTextMenuTitle);
}
}
/**
* Returns whether this text view is a current input method target. The
* default implementation just checks with {@link InputMethodManager}.
*/
public boolean isInputMethodTarget() {
InputMethodManager imm = InputMethodManager.peekInstance();
return imm != null && imm.isActive(this);
}
// Selection context mode
private static final int ID_SELECT_ALL = android.R.id.selectAll;
private static final int ID_CUT = android.R.id.cut;
private static final int ID_COPY = android.R.id.copy;
private static final int ID_PASTE = android.R.id.paste;
// Context menu entries
private static final int ID_COPY_URL = android.R.id.copyUrl;
private static final int ID_SELECTION_MODE = android.R.id.selectTextMode;
private class MenuHandler implements MenuItem.OnMenuItemClickListener {
public boolean onMenuItemClick(MenuItem item) {
return onTextContextMenuItem(item.getItemId());
}
}
/**
* Called when a context menu option for the text view is selected. Currently
* this will be {@link android.R.id#copyUrl} or {@link android.R.id#selectTextMode}.
*/
public boolean onTextContextMenuItem(int id) {
int min = 0;
int max = mText.length();
if (isFocused()) {
final int selStart = getSelectionStart();
final int selEnd = getSelectionEnd();
min = Math.max(0, Math.min(selStart, selEnd));
max = Math.max(0, Math.max(selStart, selEnd));
}
ClipboardManager clipboard = (ClipboardManager)getContext()
.getSystemService(Context.CLIPBOARD_SERVICE);
switch (id) {
case ID_COPY_URL:
URLSpan[] urls = ((Spanned) mText).getSpans(min, max, URLSpan.class);
if (urls.length >= 1) {
ClipData clip = null;
for (int i=0; i 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) {
// Two spaces at beginning of paste: remove one
final int originalLength = mText.length();
((Editable) mText).replace(min - 1, min, "");
// Due to filters, there is no garantee that exactly one character was
// removed. Count instead.
final int delta = mText.length() - originalLength;
min += delta;
max += delta;
}
} else {
if (min > 0 && !Character.isSpaceChar(mTransformed.charAt(min - 1))) {
// No space at beginning of paste: add one
final int originalLength = mText.length();
((Editable) mText).replace(min, min, " ");
// Taking possible filters into account as above.
final int delta = mText.length() - originalLength;
min += delta;
max += delta;
}
}
if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) {
// Two spaces at end of paste: remove one
((Editable) mText).replace(max, max + 1, "");
}
} else {
if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) {
// No space at end of paste: add one
((Editable) mText).replace(max, max, " ");
}
}
return packRangeInLong(min, max);
}
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
mEatTouchRelease = true;
return true;
}
if (startSelectionActionMode()) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mEatTouchRelease = true;
return true;
}
return false;
}
private boolean touchPositionIsInSelection() {
int selectionStart = getSelectionStart();
int selectionEnd = getSelectionEnd();
if (selectionStart == selectionEnd) {
return false;
}
if (selectionStart > selectionEnd) {
int tmp = selectionStart;
selectionStart = selectionEnd;
selectionEnd = tmp;
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
}
SelectionModifierCursorController selectionModifierCursorController =
((SelectionModifierCursorController) mSelectionModifierCursorController);
int minOffset = selectionModifierCursorController.getMinTouchOffset();
int maxOffset = selectionModifierCursorController.getMaxTouchOffset();
return ((minOffset >= selectionStart) && (maxOffset < selectionEnd));
}
/**
* Provides the callback used to start a selection action mode.
*
* @return A callback instance that will be used to start selection mode, or null if selection
* mode is not available.
*/
private ActionMode.Callback getActionModeCallback() {
// Long press in the current selection.
// Should initiate a drag. Return false, to rely on context menu for now.
if (canSelectText() && !touchPositionIsInSelection()) {
return new SelectionActionModeCallback();
}
return null;
}
/**
*
* @return true if the selection mode was actually started.
*/
private boolean startSelectionActionMode() {
if (mSelectionActionMode != null) {
// Selection action mode is already started
return false;
}
ActionMode.Callback actionModeCallback = getActionModeCallback();
if (actionModeCallback != null) {
mSelectionActionMode = startActionMode(actionModeCallback);
return mSelectionActionMode != null;
}
return false;
}
/**
* Same as {@link #stopSelectionActionMode()}, except that there is no cursor controller
* fade out animation. Needed since the drawable and their alpha values are shared by all
* TextViews. Switching from one TextView to another would fade the cursor controllers in the
* new one otherwise.
*/
private void terminateSelectionActionMode() {
stopSelectionActionMode();
if (mSelectionModifierCursorController != null) {
SelectionModifierCursorController selectionModifierCursorController =
(SelectionModifierCursorController) mSelectionModifierCursorController;
selectionModifierCursorController.cancelFadeOutAnimation();
}
}
private void stopSelectionActionMode() {
if (mSelectionActionMode != null) {
mSelectionActionMode.finish();
}
}
private class SelectionActionModeCallback implements ActionMode.Callback {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
if (mSelectionModifierCursorController == null) {
Log.w(LOG_TAG, "TextView has no selection controller. Action mode cancelled.");
return false;
}
if (!requestFocus()) {
return false;
}
mode.setTitle(mContext.getString(com.android.internal.R.string.textSelectionCABTitle));
mode.setSubtitle(null);
selectCurrentWord();
boolean atLeastOne = false;
if (canSelectText()) {
menu.add(0, ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
setIcon(com.android.internal.R.drawable.ic_menu_select_all).
setAlphabeticShortcut('a');
atLeastOne = true;
}
if (canCut()) {
menu.add(0, ID_CUT, 0, com.android.internal.R.string.cut).
setIcon(com.android.internal.R.drawable.ic_menu_cut).
setAlphabeticShortcut('x');
atLeastOne = true;
}
if (canCopy()) {
menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy).
setIcon(com.android.internal.R.drawable.ic_menu_copy).
setAlphabeticShortcut('c');
atLeastOne = true;
}
if (canPaste()) {
menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
}
setIcon(com.android.internal.R.drawable.ic_menu_paste).
setAlphabeticShortcut('v');
atLeastOne = true;
}
if (atLeastOne) {
mSelectionModifierCursorController.show();
return true;
} else {
return false;
}
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
final int itemId = item.getItemId();
if (itemId == ID_SELECT_ALL) {
Selection.setSelection((Spannable) mText, 0, mText.length());
// Update controller positions after selection change.
if (mSelectionModifierCursorController != null) {
mSelectionModifierCursorController.show();
}
return true;
}
ClipboardManager clipboard = (ClipboardManager) getContext().
getSystemService(Context.CLIPBOARD_SERVICE);
int min = 0;
int max = mText.length();
if (isFocused()) {
final int selStart = getSelectionStart();
final int selEnd = getSelectionEnd();
min = Math.max(0, Math.min(selStart, selEnd));
max = Math.max(0, Math.max(selStart, selEnd));
}
switch (item.getItemId()) {
case ID_PASTE:
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
boolean didfirst = false;
for (int i=0; i= clip.left && posX <= clip.right &&
posY >= clip.top && posY <= clip.bottom;
}
private void moveTo(int x, int y) {
mPositionX = x - TextView.this.mScrollX;
mPositionY = y - TextView.this.mScrollY;
if (isPositionVisible()) {
int[] coords = null;
if (mContainer.isShowing()){
coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
mContainer.update(coords[0] + mPositionX, coords[1] + mPositionY,
mRight - mLeft, mBottom - mTop);
} else {
show();
}
if (mIsDragging) {
if (coords == null) {
coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
}
if (coords[0] != mLastParentX || coords[1] != mLastParentY) {
mTouchToWindowOffsetX += coords[0] - mLastParentX;
mTouchToWindowOffsetY += coords[1] - mLastParentY;
mLastParentX = coords[0];
mLastParentY = coords[1];
}
}
} else {
hide();
}
}
@Override
public void onDraw(Canvas c) {
mDrawable.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
if (mPositionOnTop) {
c.save();
c.rotate(180, (mRight - mLeft) / 2, (mBottom - mTop) / 2);
mDrawable.draw(c);
c.restore();
} else {
mDrawable.draw(c);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
mTouchToWindowOffsetX = rawX - mPositionX;
mTouchToWindowOffsetY = rawY - mPositionY;
final int[] coords = mTempCoords;
TextView.this.getLocationInWindow(coords);
mLastParentX = coords[0];
mLastParentY = coords[1];
mIsDragging = true;
break;
}
case MotionEvent.ACTION_MOVE: {
final float rawX = ev.getRawX();
final float rawY = ev.getRawY();
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY + mTouchOffsetY;
mController.updatePosition(this, (int) Math.round(newPosX),
(int) Math.round(newPosY));
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
}
return true;
}
public boolean isDragging() {
return mIsDragging;
}
void positionAtCursor(final int offset, boolean bottom) {
final int width = mDrawable.getIntrinsicWidth();
final int height = mDrawable.getIntrinsicHeight();
final int line = mLayout.getLineForOffset(offset);
final int lineTop = mLayout.getLineTop(line);
final int lineBottom = mLayout.getLineBottom(line);
final Rect bounds = sCursorControllerTempRect;
bounds.left = (int) (mLayout.getPrimaryHorizontal(offset) - mHotspotX)
+ TextView.this.mScrollX;
bounds.top = (bottom ? lineBottom : lineTop - mHeight) + TextView.this.mScrollY;
bounds.right = bounds.left + width;
bounds.bottom = bounds.top + height;
convertFromViewportToContentCoordinates(bounds);
moveTo(bounds.left, bounds.top);
}
}
private class InsertionPointCursorController implements CursorController {
private static final int DELAY_BEFORE_FADE_OUT = 4100;
// The cursor controller image
private final HandleView mHandle;
private final Runnable mHider = new Runnable() {
public void run() {
hide();
}
};
InsertionPointCursorController() {
mHandle = new HandleView(this, HandleView.CENTER);
}
public void show() {
updatePosition();
mHandle.show();
hideDelayed(DELAY_BEFORE_FADE_OUT);
public void hide() {
mHandle.hide();
TextView.this.removeCallbacks(mHider);
}
private void hideDelayed(int msec) {
TextView.this.removeCallbacks(mHider);
TextView.this.postDelayed(mHider, msec);
}
public boolean isShowing() {
return mHandle.isShowing();
}
public void updatePosition(HandleView handle, int x, int y) {
final int previousOffset = getSelectionStart();
int offset = getHysteresisOffset(x, y, previousOffset);
if (offset != previousOffset) {
Selection.setSelection((Spannable) mText, offset);
updatePosition();
}
hideDelayed(DELAY_BEFORE_FADE_OUT);
}
public void updatePosition() {
final int offset = getSelectionStart();
if (offset < 0) {
// Should never happen, safety check.
Log.w(LOG_TAG, "Update cursor controller position called with no cursor");
hide();
return;
}
mHandle.positionAtCursor(offset, true);
}
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
public void onTouchModeChanged(boolean isInTouchMode) {
if (!isInTouchMode) {
hide();
}
}
}
private class SelectionModifierCursorController implements CursorController {
// The cursor controller images
private HandleView mStartHandle, mEndHandle;
// The offsets of that last touch down event. Remembered to start selection there.
private int mMinTouchOffset, mMaxTouchOffset;
// Whether selection anchors are active
private boolean mIsShowing;
private static final int DELAY_BEFORE_FADE_OUT = 4100;
private final Runnable mHider = new Runnable() {
public void run() {
hide();
}
};
SelectionModifierCursorController() {
mStartHandle = new HandleView(this, HandleView.LEFT);
mEndHandle = new HandleView(this, HandleView.RIGHT);
}
public void show() {
mIsShowing = true;
updatePosition();
mStartHandle.show();
mEndHandle.show();
hideInsertionPointCursorController();
hideDelayed(DELAY_BEFORE_FADE_OUT);
}
public void hide() {
mStartHandle.hide();
mEndHandle.hide();
mIsShowing = false;
removeCallbacks(mHider);
}
private void hideDelayed(int delay) {
removeCallbacks(mHider);
postDelayed(mHider, delay);
}
public boolean isShowing() {
return mIsShowing;
}
public void cancelFadeOutAnimation() {
hide();
}
public void updatePosition(HandleView handle, int x, int y) {
int selectionStart = getSelectionStart();
int selectionEnd = getSelectionEnd();
final int previousOffset = handle == mStartHandle ? selectionStart : selectionEnd;
int offset = getHysteresisOffset(x, y, previousOffset);
// Handle the case where start and end are swapped, making sure start <= end
if (handle == mStartHandle) {
if (selectionStart == offset || offset > selectionEnd) {
return; // no change, no need to redraw;
}
// If the user "closes" the selection entirely they were probably trying to
// select a single character. Help them out.
if (offset == selectionEnd) {
offset = selectionEnd - 1;
}
selectionStart = offset;
} else {
if (selectionEnd == offset || offset < selectionStart) {
return; // no change, no need to redraw;
}
// If the user "closes" the selection entirely they were probably trying to
// select a single character. Help them out.
if (offset == selectionStart) {
offset = selectionStart + 1;
}
selectionEnd = offset;
}
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
updatePosition();
}
public void updatePosition() {
final int selectionStart = getSelectionStart();
final int selectionEnd = getSelectionEnd();
if ((selectionStart < 0) || (selectionEnd < 0)) {
// Should never happen, safety check.
Log.w(LOG_TAG, "Update selection controller position called with no cursor");
hide();
return;
}
mStartHandle.positionAtCursor(selectionStart, true);
mEndHandle.positionAtCursor(selectionEnd, true);
hideDelayed(DELAY_BEFORE_FADE_OUT);
}
public boolean onTouchEvent(MotionEvent event) {
if (isFocused() && isTextEditable()) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
final int x = (int) event.getX();
final int y = (int) event.getY();
// Remember finger down position, to be able to start selection from there
mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y);
break;
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_POINTER_UP:
// Handle multi-point gestures. Keep min and max offset positions.
// Only activated for devices that correctly handle multi-touch.
if (mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) {
updateMinAndMaxOffsets(event);
}
break;
}
}
return false;
}
private void updateMinAndMaxOffsets(MotionEvent event) {
int pointerCount = event.getPointerCount();
for (int index = 0; index < pointerCount; index++) {
final int x = (int) event.getX(index);
final int y = (int) event.getY(index);
int offset = getOffset(x, y);
if (offset < mMinTouchOffset) mMinTouchOffset = offset;
if (offset > mMaxTouchOffset) mMaxTouchOffset = offset;
}
}
public int getMinTouchOffset() {
return mMinTouchOffset;
}
public int getMaxTouchOffset() {
return mMaxTouchOffset;
* @return true iff this controller is currently used to move the selection start.
*/
public boolean isSelectionStartDragged() {
return mStartHandle.isDragging();
}
public void onTouchModeChanged(boolean isInTouchMode) {
if (!isInTouchMode) {
hide();
}
}
}
private void hideInsertionPointCursorController() {
if (mInsertionPointCursorController != null) {
mInsertionPointCursorController.hide();
}
}
private void hideControllers() {
hideInsertionPointCursorController();
stopSelectionActionMode();
}
private int getOffsetForHorizontal(int line, int x) {
x -= getTotalPaddingLeft();
// Clamp the position to inside of the view.
x = Math.max(0, x);
x = Math.min(getWidth() - getTotalPaddingRight() - 1, x);
x += getScrollX();
return getLayout().getOffsetForHorizontal(line, x);
}
/**
* Get the offset character closest to the specified absolute position.
*
* @param x The horizontal absolute position of a point on screen
* @param y The vertical absolute position of a point on screen
* @return the character offset for the character whose position is closest to the specified
* position. Returns -1 if there is no layout.
*
* @hide
*/
public int getOffset(int x, int y) {
if (getLayout() == null) return -1;
y -= getTotalPaddingTop();
// Clamp the position to inside of the view.
y = Math.max(0, y);
y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
y += getScrollY();
final int line = getLayout().getLineForVertical(y);
final int offset = getOffsetForHorizontal(line, x);
return offset;
}
int getHysteresisOffset(int x, int y, int previousOffset) {
final Layout layout = getLayout();
if (layout == null) return -1;
y -= getTotalPaddingTop();
// Clamp the position to inside of the view.
y = Math.max(0, y);
y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
y += getScrollY();
int line = getLayout().getLineForVertical(y);
final int previousLine = layout.getLineForOffset(previousOffset);
final int previousLineTop = layout.getLineTop(previousLine);
final int previousLineBottom = layout.getLineBottom(previousLine);
final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 8;
// If new line is just before or after previous line and y position is less than
// hysteresisThreshold away from previous line, keep cursor on previous line.
private static final int ANIMATED_SCROLL_GAP = 250;
if (((line == previousLine + 1) && ((y - previousLineBottom) < hysteresisThreshold)) ||
((line == previousLine - 1) && ((previousLineTop - y) < hysteresisThreshold))) {
line = previousLine;
}
return getOffsetForHorizontal(line, x);
}
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
private BufferType mBufferType = BufferType.NORMAL;
private int mInputType = EditorInfo.TYPE_NULL;
private CharSequence mHint;
private Layout mHintLayout;
private KeyListener mInput;
private MovementMethod mMovement;
private TransformationMethod mTransformation;
private ChangeWatcher mChangeWatcher;
private ArrayList mListeners = null;
// display attributes
private final TextPaint mTextPaint;
private boolean mUserSetTextScaleX;
private final Paint mHighlightPaint;
private int mHighlightColor = 0xCC475925;
private Layout mLayout;
private long mShowCursor;
private Blink mBlink;
private boolean mCursorVisible = true;
// Cursor Controllers. Null when disabled.
private CursorController mInsertionPointCursorController;
private CursorController mSelectionModifierCursorController;
private ActionMode mSelectionActionMode;
private int mLastTouchOffset = -1;
// These are needed to desambiguate a long click. If the long click comes from ones of these, we
// select from the current cursor position. Otherwise, select from long pressed position.
private boolean mDPadCenterIsDown = false;
private boolean mEnterKeyIsDown = false;
// Created once and shared by different CursorController helper methods.
// Only one cursor controller is active at any time which prevent race conditions.
private static Rect sCursorControllerTempRect = new Rect();
private boolean mSelectAllOnFocus = false;
private int mGravity = Gravity.TOP | Gravity.LEFT;
private boolean mHorizontallyScrolling;
private int mAutoLinkMask;
private boolean mLinksClickable = true;
private float mSpacingMult = 1;
private float mSpacingAdd = 0;
private static final int LINES = 1;
private static final int EMS = LINES;
private static final int PIXELS = 2;
private int mMaximum = Integer.MAX_VALUE;
private int mMaxMode = LINES;
private int mMinimum = 0;
private int mMinMode = LINES;
private int mMaxWidth = Integer.MAX_VALUE;
private int mMaxWidthMode = PIXELS;
private int mMinWidth = 0;
private int mMinWidthMode = PIXELS;
private boolean mSingleLine;
private int mDesiredHeightAtMeasure = -1;
private boolean mIncludePad = true;
// tmp primitives, so we don't alloc them on each draw
private Path mHighlightPath;
private boolean mHighlightPathBogus = true;
private static final RectF sTempRect = new RectF();
// XXX should be much larger
private static final int VERY_WIDE = 16384;
private static final int BLINK = 500;
private long mLastScroll;
private Scroller mScroller = null;
private BoringLayout.Metrics mBoring;
private BoringLayout.Metrics mHintBoring;
private BoringLayout mSavedLayout, mSavedHintLayout;
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
private InputFilter[] mFilters = NO_FILTERS;
private static final Spanned EMPTY_SPANNED = new SpannedString("");
} |