Methods Summary |
---|
private boolean | alreadyHasChip(int start, int end)
if (mNoChips) {
return true;
}
DrawableRecipientChip[] chips =
getSpannable().getSpans(start, end, DrawableRecipientChip.class);
if ((chips == null || chips.length == 0)) {
return false;
}
return true;
|
public void | append(java.lang.CharSequence text, int start, int end)Convenience method: Append the specified text slice to the TextView's
display buffer, upgrading it to BufferType.EDITABLE if it was
not already editable. Commas are excluded as they are added automatically
by the view.
// We don't care about watching text changes while appending.
if (mTextWatcher != null) {
removeTextChangedListener(mTextWatcher);
}
super.append(text, start, end);
if (!TextUtils.isEmpty(text) && TextUtils.getTrimmedLength(text) > 0) {
String displayString = text.toString();
if (!displayString.trim().endsWith(String.valueOf(COMMIT_CHAR_COMMA))) {
// We have no separator, so we should add it
super.append(SEPARATOR, 0, SEPARATOR.length());
displayString += SEPARATOR;
}
if (!TextUtils.isEmpty(displayString)
&& TextUtils.getTrimmedLength(displayString) > 0) {
mPendingChipsCount++;
mPendingChips.add(displayString);
}
}
// Put a message on the queue to make sure we ALWAYS handle pending
// chips.
if (mPendingChipsCount > 0) {
postHandlePendingChips();
}
mHandler.post(mAddTextWatcher);
|
public void | appendRecipientEntry(RecipientEntry entry)Append a new {@link RecipientEntry} to the end of the recipient chips, leaving any
unfinished text at the end.
clearComposingText();
final Editable editable = getText();
int chipInsertionPoint = 0;
// Find the end of last chip and see if there's any unchipified text.
final DrawableRecipientChip[] recips = getSortedRecipients();
if (recips != null && recips.length > 0) {
final DrawableRecipientChip last = recips[recips.length - 1];
// The chip will be inserted at the end of last chip + 1. All the unfinished text after
// the insertion point will be kept untouched.
chipInsertionPoint = editable.getSpanEnd(last) + 1;
}
final CharSequence chip = createChip(entry, false);
if (chip != null) {
editable.insert(chipInsertionPoint, chip);
}
|
private float | calculateAvailableWidth()Get the max amount of space a chip can take up. The formula takes into
account the width of the EditTextView, any view padding, and padding
that will be added to the chip.
return getWidth() - getPaddingLeft() - getPaddingRight() - mChipTextStartPadding
- mChipTextEndPadding;
|
private int | calculateOffsetFromBottom(int line)Calculate the bottom of the line the chip will be located on using:
1) which line the chip appears on
2) the height of a chip
3) padding built into the edit text view
// Line offsets start at zero.
int actualLine = getLineCount() - (line + 1);
return -((actualLine * ((int) mChipHeight) + getPaddingBottom()) + getPaddingTop())
+ getDropDownVerticalOffset();
|
private int | calculateOffsetFromBottomToTop(int line)Calculate the offset from bottom of the EditText to top of the provided line.
return -(int) ((mChipHeight + (2 * mLineSpacingExtra)) * (Math
.abs(getLineCount() - line)) + getPaddingBottom());
|
private int | calculateTextHeight()
final Rect textBounds = new Rect();
final TextPaint paint = getPaint();
textBounds.setEmpty();
// First measure the bounds of a sample text.
final String textHeightSample = "a";
paint.getTextBounds(textHeightSample, 0, textHeightSample.length(), textBounds);
textBounds.left = 0;
textBounds.right = 0;
return textBounds.height();
|
private void | checkChipWidths()
// Check the widths of the associated chips.
DrawableRecipientChip[] chips = getSortedRecipients();
if (chips != null) {
Rect bounds;
for (DrawableRecipientChip chip : chips) {
bounds = chip.getBounds();
if (getWidth() > 0 && bounds.right - bounds.left >
getWidth() - getPaddingLeft() - getPaddingRight()) {
// Need to redraw that chip.
replaceChip(chip, chip.getEntry());
}
}
}
|
private boolean | chipsPending()
return mPendingChipsCount > 0 || (mRemovedSpans != null && mRemovedSpans.size() > 0);
|
private void | clearSelectedChip()
if (mSelectedChip != null) {
unselectChip(mSelectedChip);
mSelectedChip = null;
}
setCursorVisible(true);
|
private void | commitByCharacter()
// We can't possibly commit by character if we can't tokenize.
if (mTokenizer == null) {
return;
}
Editable editable = getText();
int end = getSelectionEnd();
int start = mTokenizer.findTokenStart(editable, end);
if (shouldCreateChip(start, end)) {
commitChip(start, end, editable);
}
setSelection(getText().length());
|
private boolean | commitChip(int start, int end, android.text.Editable editable)
ListAdapter adapter = getAdapter();
if (adapter != null && adapter.getCount() > 0 && enoughToFilter()
&& end == getSelectionEnd() && !isPhoneQuery()) {
// let's choose the selected or first entry if only the input text is NOT an email
// address so we won't try to replace the user's potentially correct but
// new/unencountered email input
if (!isValidEmailAddress(editable.toString().substring(start, end).trim())) {
final int selectedPosition = getListSelection();
if (selectedPosition == -1) {
// Nothing is selected; use the first item
submitItemAtPosition(0);
} else {
submitItemAtPosition(selectedPosition);
}
}
dismissDropDown();
return true;
} else {
int tokenEnd = mTokenizer.findTokenEnd(editable, start);
if (editable.length() > tokenEnd + 1) {
char charAt = editable.charAt(tokenEnd + 1);
if (charAt == COMMIT_CHAR_COMMA || charAt == COMMIT_CHAR_SEMICOLON) {
tokenEnd++;
}
}
String text = editable.toString().substring(start, tokenEnd).trim();
clearComposingText();
if (text != null && text.length() > 0 && !text.equals(" ")) {
RecipientEntry entry = createTokenizedEntry(text);
if (entry != null) {
QwertyKeyListener.markAsReplaced(editable, start, end, "");
CharSequence chipText = createChip(entry, false);
if (chipText != null && start > -1 && end > -1) {
editable.replace(start, end, chipText);
}
}
// Only dismiss the dropdown if it is related to the text we
// just committed.
// For paste, it may not be as there are possibly multiple
// tokens being added.
if (end == getSelectionEnd()) {
dismissDropDown();
}
sanitizeBetween();
return true;
}
}
return false;
|
private boolean | commitDefault()Create a chip from the default selection. If the popup is showing, the
default is the selected item (if one is selected), or the first item, in the popup
suggestions list. Otherwise, it is whatever the user had typed in. End represents where the
tokenizer should search for a token to turn into a chip.
// If there is no tokenizer, don't try to commit.
if (mTokenizer == null) {
return false;
}
Editable editable = getText();
int end = getSelectionEnd();
int start = mTokenizer.findTokenStart(editable, end);
if (shouldCreateChip(start, end)) {
int whatEnd = mTokenizer.findTokenEnd(getText(), start);
// In the middle of chip; treat this as an edit
// and commit the whole token.
whatEnd = movePastTerminators(whatEnd);
if (whatEnd != getSelectionEnd()) {
handleEdit(start, whatEnd);
return true;
}
return commitChip(start, end , editable);
}
return false;
|
private com.android.ex.chips.recipientchip.DrawableRecipientChip | constructChipSpan(RecipientEntry contact, boolean pressed)
TextPaint paint = getPaint();
float defaultSize = paint.getTextSize();
int defaultColor = paint.getColor();
Bitmap tmpBitmap;
if (pressed) {
tmpBitmap = createSelectedChip(contact, paint);
} else {
tmpBitmap = createUnselectedChip(contact, paint);
}
// Pass the full text, un-ellipsized, to the chip.
Drawable result = new BitmapDrawable(getResources(), tmpBitmap);
result.setBounds(0, 0, tmpBitmap.getWidth(), tmpBitmap.getHeight());
VisibleRecipientChip recipientChip =
new VisibleRecipientChip(result, contact);
recipientChip.setExtraMargin(mLineSpacingExtra);
// Return text to the original size.
paint.setTextSize(defaultSize);
paint.setColor(defaultColor);
return recipientChip;
|
private android.graphics.drawable.StateListDrawable | constructStateListDeleteDrawable()
// Construct the StateListDrawable from deleteDrawable
StateListDrawable deleteDrawable = new StateListDrawable();
if (!mDisableDelete) {
deleteDrawable.addState(new int[]{android.R.attr.state_activated}, mChipDelete);
}
deleteDrawable.addState(new int[0], null);
return deleteDrawable;
|
int | countTokens(android.text.Editable text)
int tokenCount = 0;
int start = 0;
while (start < text.length()) {
start = movePastTerminators(mTokenizer.findTokenEnd(text, start));
tokenCount++;
if (start >= text.length()) {
break;
}
}
return tokenCount;
|
java.lang.String | createAddressText(RecipientEntry entry)
String display = entry.getDisplayName();
String address = entry.getDestination();
if (TextUtils.isEmpty(display) || TextUtils.equals(display, address)) {
display = null;
}
String trimmedDisplayText;
if (isPhoneQuery() && isPhoneNumber(address)) {
trimmedDisplayText = address.trim();
} else {
if (address != null) {
// Tokenize out the address in case the address already
// contained the username as well.
Rfc822Token[] tokenized = Rfc822Tokenizer.tokenize(address);
if (tokenized != null && tokenized.length > 0) {
address = tokenized[0].getAddress();
}
}
Rfc822Token token = new Rfc822Token(display, address, null);
trimmedDisplayText = token.toString().trim();
}
int index = trimmedDisplayText.indexOf(",");
return mTokenizer != null && !TextUtils.isEmpty(trimmedDisplayText)
&& index < trimmedDisplayText.length() - 1 ? (String) mTokenizer
.terminateToken(trimmedDisplayText) : trimmedDisplayText;
|
private android.widget.ListAdapter | createAlternatesAdapter(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)
return new RecipientAlternatesAdapter(getContext(), chip.getContactId(),
chip.getDirectoryId(), chip.getLookupKey(), chip.getDataId(),
getAdapter().getQueryType(), this, mDropdownChipLayouter,
constructStateListDeleteDrawable());
|
private java.lang.CharSequence | createChip(RecipientEntry entry, boolean pressed)
final String displayText = createAddressText(entry);
if (TextUtils.isEmpty(displayText)) {
return null;
}
// Always leave a blank space at the end of a chip.
final int textLength = displayText.length() - 1;
final SpannableString chipText = new SpannableString(displayText);
if (!mNoChips) {
try {
DrawableRecipientChip chip = constructChipSpan(entry, pressed);
chipText.setSpan(chip, 0, textLength,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
chip.setOriginalText(chipText.toString());
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
return null;
}
}
onChipCreated(entry);
return chipText;
|
private com.android.ex.chips.RecipientEditTextView$ChipBitmapContainer | createChipBitmap(RecipientEntry contact, android.text.TextPaint paint, android.graphics.drawable.Drawable overrideBackgroundDrawable, int backgroundColor)
final ChipBitmapContainer result = new ChipBitmapContainer();
Rect backgroundPadding = new Rect();
if (overrideBackgroundDrawable != null) {
overrideBackgroundDrawable.getPadding(backgroundPadding);
}
// Ellipsize the text so that it takes AT MOST the entire width of the
// autocomplete text entry area. Make sure to leave space for padding
// on the sides.
int height = (int) mChipHeight;
// Since the icon is a square, it's width is equal to the maximum height it can be inside
// the chip. Don't include iconWidth for invalid contacts.
int iconWidth = contact.isValid() ?
height - backgroundPadding.top - backgroundPadding.bottom : 0;
float[] widths = new float[1];
paint.getTextWidths(" ", widths);
CharSequence ellipsizedText = ellipsizeText(createChipDisplayText(contact), paint,
calculateAvailableWidth() - iconWidth - widths[0] - backgroundPadding.left
- backgroundPadding.right);
int textWidth = (int) paint.measureText(ellipsizedText, 0, ellipsizedText.length());
// Chip start padding is the same as the end padding if there is no contact image.
final int startPadding = contact.isValid() ? mChipTextStartPadding : mChipTextEndPadding;
// Make sure there is a minimum chip width so the user can ALWAYS
// tap a chip without difficulty.
int width = Math.max(iconWidth * 2, textWidth + startPadding + mChipTextEndPadding
+ iconWidth + backgroundPadding.left + backgroundPadding.right);
// Create the background of the chip.
result.bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(result.bitmap);
// Check if the background drawable is set via attr
if (overrideBackgroundDrawable != null) {
overrideBackgroundDrawable.setBounds(0, 0, width, height);
overrideBackgroundDrawable.draw(canvas);
} else {
// Draw the default chip background
mWorkPaint.reset();
mWorkPaint.setColor(backgroundColor);
final float radius = height / 2;
canvas.drawRoundRect(new RectF(0, 0, width, height), radius, radius,
mWorkPaint);
}
// Draw the text vertically aligned
int textX = shouldPositionAvatarOnRight() ?
mChipTextEndPadding + backgroundPadding.left :
width - backgroundPadding.right - mChipTextEndPadding - textWidth;
canvas.drawText(ellipsizedText, 0, ellipsizedText.length(),
textX, getTextYOffset(height), paint);
// Set the variables that are needed to draw the icon bitmap once it's loaded
int iconX = shouldPositionAvatarOnRight() ? width - backgroundPadding.right - iconWidth :
backgroundPadding.left;
result.left = iconX;
result.top = backgroundPadding.top;
result.right = iconX + iconWidth;
result.bottom = height - backgroundPadding.bottom;
return result;
|
java.lang.String | createChipDisplayText(RecipientEntry entry)
String display = entry.getDisplayName();
String address = entry.getDestination();
if (TextUtils.isEmpty(display) || TextUtils.equals(display, address)) {
display = null;
}
if (!TextUtils.isEmpty(display)) {
return display;
} else if (!TextUtils.isEmpty(address)){
return address;
} else {
return new Rfc822Token(display, address, null).toString();
}
|
void | createMoreChip()Create the more chip. The more chip is text that replaces any chips that
do not fit in the pre-defined available space when the
RecipientEditTextView loses focus.
if (mNoChips) {
createMoreChipPlainText();
return;
}
if (!mShouldShrink) {
return;
}
ReplacementDrawableSpan[] tempMore = getSpannable().getSpans(0, getText().length(),
MoreImageSpan.class);
if (tempMore.length > 0) {
getSpannable().removeSpan(tempMore[0]);
}
DrawableRecipientChip[] recipients = getSortedRecipients();
if (recipients == null || recipients.length <= CHIP_LIMIT) {
mMoreChip = null;
return;
}
Spannable spannable = getSpannable();
int numRecipients = recipients.length;
int overage = numRecipients - CHIP_LIMIT;
MoreImageSpan moreSpan = createMoreSpan(overage);
mRemovedSpans = new ArrayList<DrawableRecipientChip>();
int totalReplaceStart = 0;
int totalReplaceEnd = 0;
Editable text = getText();
for (int i = numRecipients - overage; i < recipients.length; i++) {
mRemovedSpans.add(recipients[i]);
if (i == numRecipients - overage) {
totalReplaceStart = spannable.getSpanStart(recipients[i]);
}
if (i == recipients.length - 1) {
totalReplaceEnd = spannable.getSpanEnd(recipients[i]);
}
if (mTemporaryRecipients == null || !mTemporaryRecipients.contains(recipients[i])) {
int spanStart = spannable.getSpanStart(recipients[i]);
int spanEnd = spannable.getSpanEnd(recipients[i]);
recipients[i].setOriginalText(text.toString().substring(spanStart, spanEnd));
}
spannable.removeSpan(recipients[i]);
}
if (totalReplaceEnd < text.length()) {
totalReplaceEnd = text.length();
}
int end = Math.max(totalReplaceStart, totalReplaceEnd);
int start = Math.min(totalReplaceStart, totalReplaceEnd);
SpannableString chipText = new SpannableString(text.subSequence(start, end));
chipText.setSpan(moreSpan, 0, chipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(start, end, chipText);
mMoreChip = moreSpan;
// If adding the +more chip goes over the limit, resize accordingly.
if (!isPhoneQuery() && getLineCount() > mMaxLines) {
setMaxLines(getLineCount());
}
|
void | createMoreChipPlainText()
// Take the first <= CHIP_LIMIT addresses and get to the end of the second one.
Editable text = getText();
int start = 0;
int end = start;
for (int i = 0; i < CHIP_LIMIT; i++) {
end = movePastTerminators(mTokenizer.findTokenEnd(text, start));
start = end; // move to the next token and get its end.
}
// Now, count total addresses.
start = 0;
int tokenCount = countTokens(text);
MoreImageSpan moreSpan = createMoreSpan(tokenCount - CHIP_LIMIT);
SpannableString chipText = new SpannableString(text.subSequence(end, text.length()));
chipText.setSpan(moreSpan, 0, chipText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text.replace(end, text.length(), chipText);
mMoreChip = moreSpan;
|
private com.android.ex.chips.RecipientEditTextView$MoreImageSpan | createMoreSpan(int count)
String moreText = String.format(mMoreItem.getText().toString(), count);
mWorkPaint.set(getPaint());
mWorkPaint.setTextSize(mMoreItem.getTextSize());
mWorkPaint.setColor(mMoreItem.getCurrentTextColor());
final int width = (int) mWorkPaint.measureText(moreText) + mMoreItem.getPaddingLeft()
+ mMoreItem.getPaddingRight();
final int height = (int) mChipHeight;
Bitmap drawable = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(drawable);
int adjustedHeight = height;
Layout layout = getLayout();
if (layout != null) {
adjustedHeight -= layout.getLineDescent(0);
}
canvas.drawText(moreText, 0, moreText.length(), 0, adjustedHeight, mWorkPaint);
Drawable result = new BitmapDrawable(getResources(), drawable);
result.setBounds(0, 0, width, height);
return new MoreImageSpan(result);
|
void | createReplacementChip(int tokenStart, int tokenEnd, android.text.Editable editable, boolean visible)Create a chip that represents just the email address of a recipient. At some later
point, this chip will be attached to a real contact entry, if one exists.
if (alreadyHasChip(tokenStart, tokenEnd)) {
// There is already a chip present at this location.
// Don't recreate it.
return;
}
String token = editable.toString().substring(tokenStart, tokenEnd);
final String trimmedToken = token.trim();
int commitCharIndex = trimmedToken.lastIndexOf(COMMIT_CHAR_COMMA);
if (commitCharIndex != -1 && commitCharIndex == trimmedToken.length() - 1) {
token = trimmedToken.substring(0, trimmedToken.length() - 1);
}
RecipientEntry entry = createTokenizedEntry(token);
if (entry != null) {
DrawableRecipientChip chip = null;
try {
if (!mNoChips) {
chip = visible ?
constructChipSpan(entry, false) : new InvisibleRecipientChip(entry);
}
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
}
editable.setSpan(chip, tokenStart, tokenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// Add this chip to the list of entries "to replace"
if (chip != null) {
if (mTemporaryRecipients == null) {
mTemporaryRecipients = new ArrayList<DrawableRecipientChip>();
}
chip.setOriginalText(token);
mTemporaryRecipients.add(chip);
}
}
|
private android.graphics.Bitmap | createSelectedChip(RecipientEntry contact, android.text.TextPaint paint)Creates a bitmap of the given contact on a selected chip.
paint.setColor(sSelectedTextColor);
final ChipBitmapContainer bitmapContainer = createChipBitmap(contact, paint,
mChipBackgroundPressed, getResources().getColor(R.color.chip_background_selected));
if (bitmapContainer.loadIcon) {
loadAvatarIcon(contact, bitmapContainer);
}
return bitmapContainer.bitmap;
|
private android.widget.ListAdapter | createSingleAddressAdapter(com.android.ex.chips.recipientchip.DrawableRecipientChip currentChip)
return new SingleRecipientArrayAdapter(getContext(), currentChip.getEntry(),
mDropdownChipLayouter, constructStateListDeleteDrawable());
|
RecipientEntry | createTokenizedEntry(java.lang.String token)
if (TextUtils.isEmpty(token)) {
return null;
}
if (isPhoneQuery() && isPhoneNumber(token)) {
return RecipientEntry.constructFakePhoneEntry(token, true);
}
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(token);
String display = null;
boolean isValid = isValid(token);
if (isValid && tokens != null && tokens.length > 0) {
// If we can get a name from tokenizing, then generate an entry from
// this.
display = tokens[0].getName();
if (!TextUtils.isEmpty(display)) {
return RecipientEntry.constructGeneratedEntry(display, tokens[0].getAddress(),
isValid);
} else {
display = tokens[0].getAddress();
if (!TextUtils.isEmpty(display)) {
return RecipientEntry.constructFakeEntry(display, isValid);
}
}
}
// Unable to validate the token or to create a valid token from it.
// Just create a chip the user can edit.
String validatedToken = null;
if (mValidator != null && !isValid) {
// Try fixing up the entry using the validator.
validatedToken = mValidator.fixText(token).toString();
if (!TextUtils.isEmpty(validatedToken)) {
if (validatedToken.contains(token)) {
// protect against the case of a validator with a null
// domain,
// which doesn't add a domain to the token
Rfc822Token[] tokenized = Rfc822Tokenizer.tokenize(validatedToken);
if (tokenized.length > 0) {
validatedToken = tokenized[0].getAddress();
isValid = true;
}
} else {
// We ran into a case where the token was invalid and
// removed
// by the validator. In this case, just use the original
// token
// and let the user sort out the error chip.
validatedToken = null;
isValid = false;
}
}
}
// Otherwise, fallback to just creating an editable email address chip.
return RecipientEntry.constructFakeEntry(
!TextUtils.isEmpty(validatedToken) ? validatedToken : token, isValid);
|
private android.graphics.Bitmap | createUnselectedChip(RecipientEntry contact, android.text.TextPaint paint)Creates a bitmap of the given contact on a selected chip.
paint.setColor(getContext().getResources().getColor(android.R.color.black));
ChipBitmapContainer bitmapContainer = createChipBitmap(contact, paint,
getChipBackground(contact), getDefaultChipBackgroundColor(contact));
if (bitmapContainer.loadIcon) {
loadAvatarIcon(contact, bitmapContainer);
}
return bitmapContainer.bitmap;
|
private RecipientEntry | createValidatedEntry(RecipientEntry item)
if (item == null) {
return null;
}
final RecipientEntry entry;
// If the display name and the address are the same, or if this is a
// valid contact, but the destination is invalid, then make this a fake
// recipient that is editable.
String destination = item.getDestination();
if (!isPhoneQuery() && item.getContactId() == RecipientEntry.GENERATED_CONTACT) {
entry = RecipientEntry.constructGeneratedEntry(item.getDisplayName(),
destination, item.isValid());
} else if (RecipientEntry.isCreatedRecipient(item.getContactId())
&& (TextUtils.isEmpty(item.getDisplayName())
|| TextUtils.equals(item.getDisplayName(), destination)
|| (mValidator != null && !mValidator.isValid(destination)))) {
entry = RecipientEntry.constructFakeEntry(destination, item.isValid());
} else {
entry = item;
}
return entry;
|
private void | drawIcon(com.android.ex.chips.RecipientEditTextView$ChipBitmapContainer bitMapResult, android.graphics.Bitmap icon)Helper function that draws the loaded icon bitmap into the chips bitmap
final Canvas canvas = new Canvas(bitMapResult.bitmap);
final RectF src = new RectF(0, 0, icon.getWidth(), icon.getHeight());
final RectF dst = new RectF(bitMapResult.left, bitMapResult.top, bitMapResult.right,
bitMapResult.bottom);
drawIconOnCanvas(icon, canvas, src, dst);
|
protected void | drawIconOnCanvas(android.graphics.Bitmap icon, android.graphics.Canvas canvas, android.graphics.RectF src, android.graphics.RectF dst)Draws the icon onto the canvas given the source rectangle of the bitmap and the destination
rectangle of the canvas.
final Matrix matrix = new Matrix();
// Draw bitmap through shader first.
final BitmapShader shader = new BitmapShader(icon, TileMode.CLAMP, TileMode.CLAMP);
matrix.reset();
// Fit bitmap to bounds.
matrix.setRectToRect(src, dst, Matrix.ScaleToFit.FILL);
shader.setLocalMatrix(matrix);
mWorkPaint.reset();
mWorkPaint.setShader(shader);
mWorkPaint.setAntiAlias(true);
mWorkPaint.setFilterBitmap(true);
mWorkPaint.setDither(true);
canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2f, mWorkPaint);
// Then draw the border.
final float borderWidth = 1f;
mWorkPaint.reset();
mWorkPaint.setColor(Color.TRANSPARENT);
mWorkPaint.setStyle(Style.STROKE);
mWorkPaint.setStrokeWidth(borderWidth);
mWorkPaint.setAntiAlias(true);
canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2f - borderWidth / 2, mWorkPaint);
mWorkPaint.reset();
|
private java.lang.CharSequence | ellipsizeText(java.lang.CharSequence text, android.text.TextPaint paint, float maxWidth)
paint.setTextSize(mChipFontSize);
if (maxWidth <= 0 && Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Max width is negative: " + maxWidth);
}
return TextUtils.ellipsize(text, paint, maxWidth,
TextUtils.TruncateAt.END);
|
public void | enableDrag()Enables drag-and-drop for chips.
mDragEnabled = true;
|
private void | expand()
if (mShouldShrink) {
setMaxLines(Integer.MAX_VALUE);
}
removeMoreChip();
setCursorVisible(true);
Editable text = getText();
setSelection(text != null && text.length() > 0 ? text.length() : 0);
// If there are any temporary chips, try replacing them now that the user
// has expanded the field.
if (mTemporaryRecipients != null && mTemporaryRecipients.size() > 0) {
new RecipientReplacementTask().execute();
mTemporaryRecipients = null;
}
|
private com.android.ex.chips.recipientchip.DrawableRecipientChip | findChip(int offset)
DrawableRecipientChip[] chips =
getSpannable().getSpans(0, getText().length(), DrawableRecipientChip.class);
// Find the chip that contains this offset.
for (int i = 0; i < chips.length; i++) {
DrawableRecipientChip chip = chips[i];
int start = getChipStart(chip);
int end = getChipEnd(chip);
if (offset >= start && offset <= end) {
return chip;
}
}
return null;
|
private static int | findText(android.text.Editable text, int offset)
if (text.charAt(offset) != ' ") {
return offset;
}
return -1;
|
private boolean | focusNext()
View next = focusSearch(View.FOCUS_DOWN);
if (next != null) {
next.requestFocus();
return true;
}
return false;
|
public BaseRecipientAdapter | getAdapter()
return (BaseRecipientAdapter) super.getAdapter();
|
android.graphics.drawable.Drawable | getChipBackground(RecipientEntry contact)Get the background drawable for a RecipientChip.
return contact.isValid() ? mChipBackground : mInvalidChipBackground;
|
private int | getChipEnd(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)
return getSpannable().getSpanEnd(chip);
|
public float | getChipHeight()
return mChipHeight;
|
private int | getChipStart(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)
return getSpannable().getSpanStart(chip);
|
private int | getDefaultChipBackgroundColor(RecipientEntry contact)
return getResources().getColor(contact.isValid() ? R.color.chip_background :
R.color.chip_background_invalid);
|
private int | getExcessTopPadding()
if (sExcessTopPadding == -1) {
sExcessTopPadding = (int) (mChipHeight + mLineSpacingExtra);
}
return sExcessTopPadding;
|
com.android.ex.chips.recipientchip.DrawableRecipientChip | getLastChip()
DrawableRecipientChip last = null;
DrawableRecipientChip[] chips = getSortedRecipients();
if (chips != null && chips.length > 0) {
last = chips[chips.length - 1];
}
return last;
|
com.android.ex.chips.recipientchip.ReplacementDrawableSpan | getMoreChip()
MoreImageSpan[] moreSpans = getSpannable().getSpans(0, getText().length(),
MoreImageSpan.class);
return moreSpans != null && moreSpans.length > 0 ? moreSpans[0] : null;
|
protected android.widget.ScrollView | getScrollView()
return mScrollView;
|
public java.util.List | getSelectedRecipients()
DrawableRecipientChip[] chips =
getText().getSpans(0, getText().length(), DrawableRecipientChip.class);
List<RecipientEntry> results = new ArrayList();
if (chips == null) {
return results;
}
for (DrawableRecipientChip c : chips) {
results.add(c.getEntry());
}
return results;
|
com.android.ex.chips.recipientchip.DrawableRecipientChip[] | getSortedRecipients()
DrawableRecipientChip[] recips = getSpannable()
.getSpans(0, getText().length(), DrawableRecipientChip.class);
ArrayList<DrawableRecipientChip> recipientsList = new ArrayList<DrawableRecipientChip>(
Arrays.asList(recips));
final Spannable spannable = getSpannable();
Collections.sort(recipientsList, new Comparator<DrawableRecipientChip>() {
@Override
public int compare(DrawableRecipientChip first, DrawableRecipientChip second) {
int firstStart = spannable.getSpanStart(first);
int secondStart = spannable.getSpanStart(second);
if (firstStart < secondStart) {
return -1;
} else if (firstStart > secondStart) {
return 1;
} else {
return 0;
}
}
});
return recipientsList.toArray(new DrawableRecipientChip[recipientsList.size()]);
|
android.text.Spannable | getSpannable()
return getText();
|
protected float | getTextYOffset(int height)Given a height, returns a Y offset that will draw the text in the middle of the height.
return height - ((height - mTextHeight) / 2);
|
int | getViewWidth()
return getWidth();
|
private void | handleEdit(int start, int end)
if (start == -1 || end == -1) {
// This chip no longer exists in the field.
dismissDropDown();
return;
}
// This is in the middle of a chip, so select out the whole chip
// and commit it.
Editable editable = getText();
setSelection(end);
String text = getText().toString().substring(start, end);
if (!TextUtils.isEmpty(text)) {
RecipientEntry entry = RecipientEntry.constructFakeEntry(text, isValid(text));
QwertyKeyListener.markAsReplaced(editable, start, end, "");
CharSequence chipText = createChip(entry, false);
int selEnd = getSelectionEnd();
if (chipText != null && start > -1 && selEnd > -1) {
editable.replace(start, selEnd, chipText);
}
}
dismissDropDown();
|
java.util.ArrayList | handlePaste()
String text = getText().toString();
int originalTokenStart = mTokenizer.findTokenStart(text, getSelectionEnd());
String lastAddress = text.substring(originalTokenStart);
int tokenStart = originalTokenStart;
int prevTokenStart = 0;
DrawableRecipientChip findChip = null;
ArrayList<DrawableRecipientChip> created = new ArrayList<DrawableRecipientChip>();
if (tokenStart != 0) {
// There are things before this!
while (tokenStart != 0 && findChip == null && tokenStart != prevTokenStart) {
prevTokenStart = tokenStart;
tokenStart = mTokenizer.findTokenStart(text, tokenStart);
findChip = findChip(tokenStart);
if (tokenStart == originalTokenStart && findChip == null) {
break;
}
}
if (tokenStart != originalTokenStart) {
if (findChip != null) {
tokenStart = prevTokenStart;
}
int tokenEnd;
DrawableRecipientChip createdChip;
while (tokenStart < originalTokenStart) {
tokenEnd = movePastTerminators(mTokenizer.findTokenEnd(getText().toString(),
tokenStart));
commitChip(tokenStart, tokenEnd, getText());
createdChip = findChip(tokenStart);
if (createdChip == null) {
break;
}
// +1 for the space at the end.
tokenStart = getSpannable().getSpanEnd(createdChip) + 1;
created.add(createdChip);
}
}
}
// Take a look at the last token. If the token has been completed with a
// commit character, create a chip.
if (isCompletedToken(lastAddress)) {
Editable editable = getText();
tokenStart = editable.toString().indexOf(lastAddress, originalTokenStart);
commitChip(tokenStart, editable.length(), editable);
created.add(findChip(tokenStart));
}
return created;
|
private void | handlePasteAndReplace()
ArrayList<DrawableRecipientChip> created = handlePaste();
if (created != null && created.size() > 0) {
// Perform reverse lookups on the pasted contacts.
IndividualReplacementTask replace = new IndividualReplacementTask();
replace.execute(created);
}
|
void | handlePasteClip(android.content.ClipData clip)Handles pasting a {@link ClipData} to this {@link RecipientEditTextView}.
if (clip == null) {
// Do nothing.
return;
}
final ClipDescription clipDesc = clip.getDescription();
boolean containsSupportedType = clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) ||
clipDesc.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML);
if (!containsSupportedType) {
return;
}
removeTextChangedListener(mTextWatcher);
final ClipDescription clipDescription = clip.getDescription();
for (int i = 0; i < clip.getItemCount(); i++) {
final String mimeType = clipDescription.getMimeType(i);
final boolean supportedType = ClipDescription.MIMETYPE_TEXT_PLAIN.equals(mimeType) ||
ClipDescription.MIMETYPE_TEXT_HTML.equals(mimeType);
if (!supportedType) {
// Only plain text and html can be pasted.
continue;
}
final CharSequence pastedItem = clip.getItemAt(i).getText();
if (!TextUtils.isEmpty(pastedItem)) {
final Editable editable = getText();
final int start = getSelectionStart();
final int end = getSelectionEnd();
if (start < 0 || end < 1) {
// No selection.
editable.append(pastedItem);
} else if (start == end) {
// Insert at position.
editable.insert(start, pastedItem);
} else {
editable.append(pastedItem, start, end);
}
handlePasteAndReplace();
}
}
mHandler.post(mAddTextWatcher);
|
void | handlePendingChips()
if (getViewWidth() <= 0) {
// The widget has not been sized yet.
// This will be called as a result of onSizeChanged
// at a later point.
return;
}
if (mPendingChipsCount <= 0) {
return;
}
synchronized (mPendingChips) {
Editable editable = getText();
// Tokenize!
if (mPendingChipsCount <= MAX_CHIPS_PARSED) {
for (int i = 0; i < mPendingChips.size(); i++) {
String current = mPendingChips.get(i);
int tokenStart = editable.toString().indexOf(current);
// Always leave a space at the end between tokens.
int tokenEnd = tokenStart + current.length() - 1;
if (tokenStart >= 0) {
// When we have a valid token, include it with the token
// to the left.
if (tokenEnd < editable.length() - 2
&& editable.charAt(tokenEnd) == COMMIT_CHAR_COMMA) {
tokenEnd++;
}
createReplacementChip(tokenStart, tokenEnd, editable, i < CHIP_LIMIT
|| !mShouldShrink);
}
mPendingChipsCount--;
}
sanitizeEnd();
} else {
mNoChips = true;
}
if (mTemporaryRecipients != null && mTemporaryRecipients.size() > 0
&& mTemporaryRecipients.size() <= RecipientAlternatesAdapter.MAX_LOOKUPS) {
if (hasFocus() || mTemporaryRecipients.size() < CHIP_LIMIT) {
new RecipientReplacementTask().execute();
mTemporaryRecipients = null;
} else {
// Create the "more" chip
mIndividualReplacements = new IndividualReplacementTask();
mIndividualReplacements.execute(new ArrayList<DrawableRecipientChip>(
mTemporaryRecipients.subList(0, CHIP_LIMIT)));
if (mTemporaryRecipients.size() > CHIP_LIMIT) {
mTemporaryRecipients = new ArrayList<DrawableRecipientChip>(
mTemporaryRecipients.subList(CHIP_LIMIT,
mTemporaryRecipients.size()));
} else {
mTemporaryRecipients = null;
}
createMoreChip();
}
} else {
// There are too many recipients to look up, so just fall back
// to showing addresses for all of them.
mTemporaryRecipients = null;
createMoreChip();
}
mPendingChipsCount = 0;
mPendingChips.clear();
}
|
boolean | isCompletedToken(java.lang.CharSequence text)
if (TextUtils.isEmpty(text)) {
return false;
}
// Check to see if this is a completed token before filtering.
int end = text.length();
int start = mTokenizer.findTokenStart(text, end);
String token = text.toString().substring(start, end).trim();
if (!TextUtils.isEmpty(token)) {
char atEnd = token.charAt(token.length() - 1);
return atEnd == COMMIT_CHAR_COMMA || atEnd == COMMIT_CHAR_SEMICOLON;
}
return false;
|
public boolean | isGeneratedContact(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)
long contactId = chip.getContactId();
return contactId == RecipientEntry.INVALID_CONTACT
|| (!isPhoneQuery() && contactId == RecipientEntry.GENERATED_CONTACT);
|
private static boolean | isPhoneNumber(java.lang.String number)
// TODO: replace this function with libphonenumber's isPossibleNumber (see
// PhoneNumberUtil). One complication is that it requires the sender's region which
// comes from the CurrentCountryIso. For now, let's just do this simple match.
if (TextUtils.isEmpty(number)) {
return false;
}
Matcher match = PHONE_PATTERN.matcher(number);
return match.matches();
|
protected boolean | isPhoneQuery()
return getAdapter() != null
&& getAdapter().getQueryType() == BaseRecipientAdapter.QUERY_TYPE_PHONE;
|
private boolean | isValid(java.lang.String text)
return mValidator == null ? true : mValidator.isValid(text);
|
private boolean | isValidEmailAddress(java.lang.String input)
return !TextUtils.isEmpty(input) && mValidator != null &&
mValidator.isValid(input);
|
public boolean | lastCharacterIsCommitCharacter(java.lang.CharSequence s)
char last;
int end = getSelectionEnd() == 0 ? 0 : getSelectionEnd() - 1;
int len = length() - 1;
if (end != len) {
last = s.charAt(end);
} else {
last = s.charAt(len);
}
return last == COMMIT_CHAR_COMMA || last == COMMIT_CHAR_SEMICOLON;
|
private void | loadAvatarIcon(RecipientEntry contact, com.android.ex.chips.RecipientEditTextView$ChipBitmapContainer bitmapContainer)Returns the avatar icon to use for this recipient entry. Returns null if we don't want to
draw an icon for this recipient.
// Don't draw photos for recipients that have been typed in OR generated on the fly.
long contactId = contact.getContactId();
boolean drawPhotos = isPhoneQuery() ?
contactId != RecipientEntry.INVALID_CONTACT
: (contactId != RecipientEntry.INVALID_CONTACT
&& contactId != RecipientEntry.GENERATED_CONTACT);
if (drawPhotos) {
final byte[] origPhotoBytes = contact.getPhotoBytes();
// There may not be a photo yet if anything but the first contact address
// was selected.
if (origPhotoBytes == null) {
// TODO: cache this in the recipient entry?
getAdapter().fetchPhoto(contact, new PhotoManager.PhotoManagerCallback() {
@Override
public void onPhotoBytesPopulated() {
// Call through to the async version which will ensure
// proper threading.
onPhotoBytesAsynchronouslyPopulated();
}
@Override
public void onPhotoBytesAsynchronouslyPopulated() {
final byte[] loadedPhotoBytes = contact.getPhotoBytes();
final Bitmap icon = BitmapFactory.decodeByteArray(loadedPhotoBytes, 0,
loadedPhotoBytes.length);
tryDrawAndInvalidate(icon);
}
@Override
public void onPhotoBytesAsyncLoadFailed() {
// TODO: can the scaled down default photo be cached?
tryDrawAndInvalidate(mDefaultContactPhoto);
}
private void tryDrawAndInvalidate(Bitmap icon) {
drawIcon(bitmapContainer, icon);
// The caller might originated from a background task. However, if the
// background task has already completed, the view might be already drawn
// on the UI but the callback would happen on the background thread.
// So if we are on a background thread, post an invalidate call to the UI.
if (Looper.myLooper() == Looper.getMainLooper()) {
// The view might not redraw itself since it's loaded asynchronously
invalidate();
} else {
post(new Runnable() {
@Override
public void run() {
invalidate();
}
});
}
}
});
} else {
final Bitmap icon = BitmapFactory.decodeByteArray(origPhotoBytes, 0,
origPhotoBytes.length);
drawIcon(bitmapContainer, icon);
}
}
|
int | movePastTerminators(int tokenEnd)
if (tokenEnd >= length()) {
return tokenEnd;
}
char atEnd = getText().toString().charAt(tokenEnd);
if (atEnd == COMMIT_CHAR_COMMA || atEnd == COMMIT_CHAR_SEMICOLON) {
tokenEnd++;
}
// This token had not only an end token character, but also a space
// separating it from the next token.
if (tokenEnd < length() && getText().toString().charAt(tokenEnd) == ' ") {
tokenEnd++;
}
return tokenEnd;
|
public boolean | onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item)
return false;
|
protected void | onAttachedToWindow()
super.onAttachedToWindow();
mAttachedToWindow = true;
|
public void | onCheckedItemChanged(int position)
ListView listView = mAlternatesPopup.getListView();
if (listView != null && listView.getCheckedItemCount() == 0) {
listView.setItemChecked(position, true);
}
mCheckedItem = position;
|
protected void | onChipCreated(RecipientEntry entry)A callback for subclasses to use to know when a chip was created with the
given RecipientEntry.
|
public void | onChipDelete()
if (mSelectedChip != null) {
removeChip(mSelectedChip);
}
mAddressPopup.dismiss();
mAlternatesPopup.dismiss();
|
public void | onClick(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)Handle click events for a chip. When a selected chip receives a click
event, see if that event was in the delete icon. If so, delete it.
Otherwise, unselect the chip.
if (chip.isSelected()) {
clearSelectedChip();
}
|
public void | onClick(android.view.View v)
// Copy this to the clipboard.
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(
Context.CLIPBOARD_SERVICE);
clipboard.setPrimaryClip(ClipData.newPlainText("", mCopyAddress));
mCopyDialog.dismiss();
|
public boolean | onCreateActionMode(android.view.ActionMode mode, android.view.Menu menu)No chips are selectable.
return false;
|
public android.view.inputmethod.InputConnection | onCreateInputConnection(android.view.inputmethod.EditorInfo outAttrs)
InputConnection connection = super.onCreateInputConnection(outAttrs);
int imeActions = outAttrs.imeOptions&EditorInfo.IME_MASK_ACTION;
if ((imeActions&EditorInfo.IME_ACTION_DONE) != 0) {
// clear the existing action
outAttrs.imeOptions ^= imeActions;
// set the DONE action
outAttrs.imeOptions |= EditorInfo.IME_ACTION_DONE;
}
if ((outAttrs.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
}
outAttrs.actionId = EditorInfo.IME_ACTION_DONE;
outAttrs.actionLabel = getContext().getString(R.string.action_label);
return connection;
|
public void | onDestroyActionMode(android.view.ActionMode mode)
|
protected void | onDetachedFromWindow()
super.onDetachedFromWindow();
mAttachedToWindow = false;
|
public void | onDismiss(android.content.DialogInterface dialog)
mCopyAddress = null;
|
public boolean | onDown(android.view.MotionEvent e)
return false;
|
public boolean | onDragEvent(android.view.DragEvent event)Handles drag event.
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// Only handle plain text drag and drop.
return event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN);
case DragEvent.ACTION_DRAG_ENTERED:
requestFocus();
return true;
case DragEvent.ACTION_DROP:
handlePasteClip(event.getClipData());
return true;
}
return false;
|
public boolean | onEditorAction(android.widget.TextView view, int action, android.view.KeyEvent keyEvent)
if (action == EditorInfo.IME_ACTION_DONE) {
if (commitDefault()) {
return true;
}
if (mSelectedChip != null) {
clearSelectedChip();
return true;
} else if (focusNext()) {
return true;
}
}
return false;
|
public boolean | onFling(android.view.MotionEvent e1, android.view.MotionEvent e2, float velocityX, float velocityY)
// Do nothing.
return false;
|
public void | onFocusChanged(boolean hasFocus, int direction, android.graphics.Rect previous)
super.onFocusChanged(hasFocus, direction, previous);
if (!hasFocus) {
shrink();
} else {
expand();
}
|
public void | onItemClick(android.widget.AdapterView parent, android.view.View view, int position, long id)When an item in the suggestions list has been clicked, create a chip from the
contact information of the selected item.
if (position < 0) {
return;
}
final int charactersTyped = submitItemAtPosition(position);
if (charactersTyped > -1 && mRecipientEntryItemClickedListener != null) {
mRecipientEntryItemClickedListener
.onRecipientEntryItemClicked(charactersTyped, position);
}
|
public boolean | onKeyDown(int keyCode, android.view.KeyEvent event)If there is a selected chip, delegate the key events
to the selected chip.
if (mSelectedChip != null && keyCode == KeyEvent.KEYCODE_DEL) {
if (mAlternatesPopup != null && mAlternatesPopup.isShowing()) {
mAlternatesPopup.dismiss();
}
removeChip(mSelectedChip);
}
switch (keyCode) {
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_DPAD_CENTER:
if (event.hasNoModifiers()) {
if (commitDefault()) {
return true;
}
if (mSelectedChip != null) {
clearSelectedChip();
return true;
} else if (focusNext()) {
return true;
}
}
break;
}
return super.onKeyDown(keyCode, event);
|
public boolean | onKeyPreIme(int keyCode, android.view.KeyEvent event)Dismiss any selected chips when the back key is pressed.
if (keyCode == KeyEvent.KEYCODE_BACK && mSelectedChip != null) {
clearSelectedChip();
return true;
}
return super.onKeyPreIme(keyCode, event);
|
public boolean | onKeyUp(int keyCode, android.view.KeyEvent event)Monitor key presses in this view to see if the user types
any commit keys, which consist of ENTER, TAB, or DPAD_CENTER.
If the user has entered text that has contact matches and types
a commit key, create a chip from the topmost matching contact.
If the user has entered text that has no contact matches and types
a commit key, then create a chip from the text they have entered.
switch (keyCode) {
case KeyEvent.KEYCODE_TAB:
if (event.hasNoModifiers()) {
if (mSelectedChip != null) {
clearSelectedChip();
} else {
commitDefault();
}
}
break;
}
return super.onKeyUp(keyCode, event);
|
public void | onLongPress(android.view.MotionEvent event)
if (mSelectedChip != null) {
return;
}
float x = event.getX();
float y = event.getY();
final int offset = putOffsetInRange(x, y);
DrawableRecipientChip currentChip = findChip(offset);
if (currentChip != null) {
if (mDragEnabled) {
// Start drag-and-drop for the selected chip.
startDrag(currentChip);
} else {
// Copy the selected chip email address.
showCopyDialog(currentChip.getEntry().getDestination());
}
}
|
public boolean | onPrepareActionMode(android.view.ActionMode mode, android.view.Menu menu)
return false;
|
public void | onRestoreInstanceState(android.os.Parcelable state)
if (!TextUtils.isEmpty(getText())) {
super.onRestoreInstanceState(null);
} else {
super.onRestoreInstanceState(state);
}
|
public android.os.Parcelable | onSaveInstanceState()
// If the user changes orientation while they are editing, just roll back the selection.
clearSelectedChip();
return super.onSaveInstanceState();
|
public boolean | onScroll(android.view.MotionEvent e1, android.view.MotionEvent e2, float distanceX, float distanceY)
// Do nothing.
return false;
|
public void | onSelectionChanged(int start, int end)
// When selection changes, see if it is inside the chips area.
// If so, move the cursor back after the chips again.
DrawableRecipientChip last = getLastChip();
if (last != null && start < getSpannable().getSpanEnd(last)) {
// Grab the last chip and set the cursor to after it.
setSelection(Math.min(getSpannable().getSpanEnd(last) + 1, getText().length()));
}
super.onSelectionChanged(start, end);
|
public void | onShowPress(android.view.MotionEvent e)
// Do nothing.
|
public boolean | onSingleTapUp(android.view.MotionEvent e)
// Do nothing.
return false;
|
public void | onSizeChanged(int width, int height, int oldw, int oldh)
super.onSizeChanged(width, height, oldw, oldh);
if (width != 0 && height != 0) {
if (mPendingChipsCount > 0) {
postHandlePendingChips();
} else {
checkChipWidths();
}
}
// Try to find the scroll view parent, if it exists.
if (mScrollView == null && !mTriedGettingScrollView) {
ViewParent parent = getParent();
while (parent != null && !(parent instanceof ScrollView)) {
parent = parent.getParent();
}
if (parent != null) {
mScrollView = (ScrollView) parent;
}
mTriedGettingScrollView = true;
}
|
public boolean | onTextContextMenuItem(int id)
if (id == android.R.id.paste) {
ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(
Context.CLIPBOARD_SERVICE);
handlePasteClip(clipboard.getPrimaryClip());
return true;
}
return super.onTextContextMenuItem(id);
|
public boolean | onTouchEvent(android.view.MotionEvent event)Monitor touch events in the RecipientEditTextView.
If the view does not have focus, any tap on the view
will just focus the view. If the view has focus, determine
if the touch target is a recipient chip. If it is and the chip
is not selected, select it and clear any other selected chips.
If it isn't, then select that chip.
if (!isFocused()) {
// Ignore any chip taps until this view is focused.
return super.onTouchEvent(event);
}
boolean handled = super.onTouchEvent(event);
int action = event.getAction();
boolean chipWasSelected = false;
if (mSelectedChip == null) {
mGestureDetector.onTouchEvent(event);
}
if (mCopyAddress == null && action == MotionEvent.ACTION_UP) {
float x = event.getX();
float y = event.getY();
int offset = putOffsetInRange(x, y);
DrawableRecipientChip currentChip = findChip(offset);
if (currentChip != null) {
if (action == MotionEvent.ACTION_UP) {
if (mSelectedChip != null && mSelectedChip != currentChip) {
clearSelectedChip();
mSelectedChip = selectChip(currentChip);
} else if (mSelectedChip == null) {
setSelection(getText().length());
commitDefault();
mSelectedChip = selectChip(currentChip);
} else {
onClick(mSelectedChip);
}
}
chipWasSelected = true;
handled = true;
} else if (mSelectedChip != null && shouldShowEditableText(mSelectedChip)) {
chipWasSelected = true;
}
}
if (action == MotionEvent.ACTION_UP && !chipWasSelected) {
clearSelectedChip();
}
return handled;
|
protected void | performFiltering(java.lang.CharSequence text, int keyCode)Instead of filtering on the entire contents of the edit box,
this subclass method filters on the range from
{@link Tokenizer#findTokenStart} to {@link #getSelectionEnd}
if the length of that range meets or exceeds {@link #getThreshold}
and makes sure that the range is not already a Chip.
boolean isCompletedToken = isCompletedToken(text);
if (enoughToFilter() && !isCompletedToken) {
int end = getSelectionEnd();
int start = mTokenizer.findTokenStart(text, end);
// If this is a RecipientChip, don't filter
// on its contents.
Spannable span = getSpannable();
DrawableRecipientChip[] chips = span.getSpans(start, end, DrawableRecipientChip.class);
if (chips != null && chips.length > 0) {
dismissDropDown();
return;
}
} else if (isCompletedToken) {
dismissDropDown();
return;
}
super.performFiltering(text, keyCode);
|
public void | performValidation()
// Do nothing. Chips handles its own validation.
|
private void | postHandlePendingChips()
mHandler.removeCallbacks(mHandlePendingChips);
mHandler.post(mHandlePendingChips);
|
private int | putOffsetInRange(float x, float y)
final int offset;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
offset = getOffsetForPosition(x, y);
} else {
offset = supportGetOffsetForPosition(x, y);
}
return putOffsetInRange(offset);
|
private int | putOffsetInRange(int o)
int offset = o;
Editable text = getText();
int length = text.length();
// Remove whitespace from end to find "real end"
int realLength = length;
for (int i = length - 1; i >= 0; i--) {
if (text.charAt(i) == ' ") {
realLength--;
} else {
break;
}
}
// If the offset is beyond or at the end of the text,
// leave it alone.
if (offset >= realLength) {
return offset;
}
Editable editable = getText();
while (offset >= 0 && findText(editable, offset) == -1 && findChip(offset) == null) {
// Keep walking backward!
offset--;
}
return offset;
|
void | removeChip(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)Remove the chip and any text associated with it from the RecipientEditTextView.
Spannable spannable = getSpannable();
int spanStart = spannable.getSpanStart(chip);
int spanEnd = spannable.getSpanEnd(chip);
Editable text = getText();
int toDelete = spanEnd;
boolean wasSelected = chip == mSelectedChip;
// Clear that there is a selected chip before updating any text.
if (wasSelected) {
mSelectedChip = null;
}
// Always remove trailing spaces when removing a chip.
while (toDelete >= 0 && toDelete < text.length() && text.charAt(toDelete) == ' ") {
toDelete++;
}
spannable.removeSpan(chip);
if (spanStart >= 0 && toDelete > 0) {
text.delete(spanStart, toDelete);
}
if (wasSelected) {
clearSelectedChip();
}
|
void | removeMoreChip()Replace the more chip, if it exists, with all of the recipient chips it had
replaced when the RecipientEditTextView gains focus.
if (mMoreChip != null) {
Spannable span = getSpannable();
span.removeSpan(mMoreChip);
mMoreChip = null;
// Re-add the spans that were removed.
if (mRemovedSpans != null && mRemovedSpans.size() > 0) {
// Recreate each removed span.
DrawableRecipientChip[] recipients = getSortedRecipients();
// Start the search for tokens after the last currently visible
// chip.
if (recipients == null || recipients.length == 0) {
return;
}
int end = span.getSpanEnd(recipients[recipients.length - 1]);
Editable editable = getText();
for (DrawableRecipientChip chip : mRemovedSpans) {
int chipStart;
int chipEnd;
String token;
// Need to find the location of the chip, again.
token = (String) chip.getOriginalText();
// As we find the matching recipient for the remove spans,
// reduce the size of the string we need to search.
// That way, if there are duplicates, we always find the correct
// recipient.
chipStart = editable.toString().indexOf(token, end);
end = chipEnd = Math.min(editable.length(), chipStart + token.length());
// Only set the span if we found a matching token.
if (chipStart != -1) {
editable.setSpan(chip, chipStart, chipEnd,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
mRemovedSpans.clear();
}
}
|
public void | removeRecipientEntry(RecipientEntry entry)Remove all chips matching the given RecipientEntry.
final DrawableRecipientChip[] recips = getText()
.getSpans(0, getText().length(), DrawableRecipientChip.class);
for (final DrawableRecipientChip recipient : recips) {
final RecipientEntry existingEntry = recipient.getEntry();
if (existingEntry != null && existingEntry.isValid() &&
existingEntry.isSamePerson(entry)) {
removeChip(recipient);
}
}
|
public void | removeTextChangedListener(android.text.TextWatcher watcher)
mTextWatcher = null;
super.removeTextChangedListener(watcher);
|
void | replaceChip(com.android.ex.chips.recipientchip.DrawableRecipientChip chip, RecipientEntry entry)Replace this currently selected chip with a new chip
that uses the contact data provided.
boolean wasSelected = chip == mSelectedChip;
if (wasSelected) {
mSelectedChip = null;
}
int start = getChipStart(chip);
int end = getChipEnd(chip);
getSpannable().removeSpan(chip);
Editable editable = getText();
CharSequence chipText = createChip(entry, false);
if (chipText != null) {
if (start == -1 || end == -1) {
Log.e(TAG, "The chip to replace does not exist but should.");
editable.insert(0, chipText);
} else {
if (!TextUtils.isEmpty(chipText)) {
// There may be a space to replace with this chip's new
// associated space. Check for it
int toReplace = end;
while (toReplace >= 0 && toReplace < editable.length()
&& editable.charAt(toReplace) == ' ") {
toReplace++;
}
editable.replace(start, toReplace, chipText);
}
}
}
setCursorVisible(true);
if (wasSelected) {
clearSelectedChip();
}
|
protected void | replaceText(java.lang.CharSequence text)We cannot use the default mechanism for replaceText. Instead,
we override onItemClickListener so we can get all the associated
contact information including display text, address, and id.
return;
|
void | sanitizeBetween()
// Don't sanitize while we are waiting for content to chipify.
if (mPendingChipsCount > 0) {
return;
}
// Find the last chip.
DrawableRecipientChip[] recips = getSortedRecipients();
if (recips != null && recips.length > 0) {
DrawableRecipientChip last = recips[recips.length - 1];
DrawableRecipientChip beforeLast = null;
if (recips.length > 1) {
beforeLast = recips[recips.length - 2];
}
int startLooking = 0;
int end = getSpannable().getSpanStart(last);
if (beforeLast != null) {
startLooking = getSpannable().getSpanEnd(beforeLast);
Editable text = getText();
if (startLooking == -1 || startLooking > text.length() - 1) {
// There is nothing after this chip.
return;
}
if (text.charAt(startLooking) == ' ") {
startLooking++;
}
}
if (startLooking >= 0 && end >= 0 && startLooking < end) {
getText().delete(startLooking, end);
}
}
|
void | sanitizeEnd()Remove any characters after the last valid chip.
// Don't sanitize while we are waiting for pending chips to complete.
if (mPendingChipsCount > 0) {
return;
}
// Find the last chip; eliminate any commit characters after it.
DrawableRecipientChip[] chips = getSortedRecipients();
Spannable spannable = getSpannable();
if (chips != null && chips.length > 0) {
int end;
mMoreChip = getMoreChip();
if (mMoreChip != null) {
end = spannable.getSpanEnd(mMoreChip);
} else {
end = getSpannable().getSpanEnd(getLastChip());
}
Editable editable = getText();
int length = editable.length();
if (length > end) {
// See what characters occur after that and eliminate them.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "There were extra characters after the last tokenizable entry."
+ editable);
}
editable.delete(end + 1, length);
}
}
|
protected void | scrollBottomIntoView()
if (mScrollView != null && mShouldShrink) {
int[] location = new int[2];
getLocationOnScreen(location);
int height = getHeight();
int currentPos = location[1] + height;
// Desired position shows at least 1 line of chips below the action
// bar. We add excess padding to make sure this is always below other
// content.
int desiredPos = (int) mChipHeight + mActionBarHeight + getExcessTopPadding();
if (currentPos > desiredPos) {
mScrollView.scrollBy(0, currentPos - desiredPos);
}
}
|
private void | scrollLineIntoView(int line)
if (mScrollView != null) {
mScrollView.smoothScrollBy(0, calculateOffsetFromBottom(line));
}
|
private com.android.ex.chips.recipientchip.DrawableRecipientChip | selectChip(com.android.ex.chips.recipientchip.DrawableRecipientChip currentChip)Show specified chip as selected. If the RecipientChip is just an email address,
selecting the chip will take the contents of the chip and place it at
the end of the RecipientEditTextView for inline editing. If the
RecipientChip is a complete contact, then selecting the chip
will change the background color of the chip, show the delete icon,
and a popup window with the address in use highlighted and any other
alternate addresses for the contact.
if (shouldShowEditableText(currentChip)) {
CharSequence text = currentChip.getValue();
Editable editable = getText();
Spannable spannable = getSpannable();
int spanStart = spannable.getSpanStart(currentChip);
int spanEnd = spannable.getSpanEnd(currentChip);
spannable.removeSpan(currentChip);
editable.delete(spanStart, spanEnd);
setCursorVisible(true);
setSelection(editable.length());
editable.append(text);
return constructChipSpan(
RecipientEntry.constructFakeEntry((String) text, isValid(text.toString())),
true);
} else {
int start = getChipStart(currentChip);
int end = getChipEnd(currentChip);
getSpannable().removeSpan(currentChip);
DrawableRecipientChip newChip;
final boolean showAddress =
currentChip.getContactId() == RecipientEntry.GENERATED_CONTACT ||
getAdapter().forceShowAddress();
try {
if (showAddress && mNoChips) {
return null;
}
newChip = constructChipSpan(currentChip.getEntry(), true);
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
return null;
}
Editable editable = getText();
QwertyKeyListener.markAsReplaced(editable, start, end, "");
if (start == -1 || end == -1) {
Log.d(TAG, "The chip being selected no longer exists but should.");
} else {
editable.setSpan(newChip, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
newChip.setSelected(true);
if (shouldShowEditableText(newChip)) {
scrollLineIntoView(getLayout().getLineForOffset(getChipStart(newChip)));
}
if (showAddress) {
showAddress(newChip, mAddressPopup);
} else {
showAlternates(newChip, mAlternatesPopup);
}
setCursorVisible(false);
return newChip;
}
|
public void | setAdapter(T adapter)
super.setAdapter(adapter);
BaseRecipientAdapter baseAdapter = (BaseRecipientAdapter) adapter;
baseAdapter.registerUpdateObserver(new BaseRecipientAdapter.EntriesUpdatedObserver() {
@Override
public void onChanged(List<RecipientEntry> entries) {
// Scroll the chips field to the top of the screen so
// that the user can see as many results as possible.
if (entries != null && entries.size() > 0) {
scrollBottomIntoView();
}
}
});
baseAdapter.setDropdownChipLayouter(mDropdownChipLayouter);
|
public void | setAlternatePopupAnchor(android.view.View v)
mAlternatePopupAnchor = v;
|
void | setChipBackground(android.graphics.drawable.Drawable chipBackground)
mChipBackground = chipBackground;
|
private void | setChipDimensions(android.content.Context context, android.util.AttributeSet attrs)
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecipientEditTextView, 0,
0);
Resources r = getContext().getResources();
mChipBackground = a.getDrawable(R.styleable.RecipientEditTextView_chipBackground);
mChipBackgroundPressed = a
.getDrawable(R.styleable.RecipientEditTextView_chipBackgroundPressed);
mInvalidChipBackground = a
.getDrawable(R.styleable.RecipientEditTextView_invalidChipBackground);
mChipDelete = a.getDrawable(R.styleable.RecipientEditTextView_chipDelete);
if (mChipDelete == null) {
mChipDelete = r.getDrawable(R.drawable.ic_cancel_wht_24dp);
}
mChipTextStartPadding = mChipTextEndPadding
= a.getDimensionPixelSize(R.styleable.RecipientEditTextView_chipPadding, -1);
if (mChipTextStartPadding == -1) {
mChipTextStartPadding = mChipTextEndPadding =
(int) r.getDimension(R.dimen.chip_padding);
}
// xml-overrides for each individual padding
// TODO: add these to attr?
int overridePadding = (int) r.getDimension(R.dimen.chip_padding_start);
if (overridePadding >= 0) {
mChipTextStartPadding = overridePadding;
}
overridePadding = (int) r.getDimension(R.dimen.chip_padding_end);
if (overridePadding >= 0) {
mChipTextEndPadding = overridePadding;
}
mDefaultContactPhoto = BitmapFactory.decodeResource(r, R.drawable.ic_contact_picture);
mMoreItem = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.more_item, null);
mChipHeight = a.getDimensionPixelSize(R.styleable.RecipientEditTextView_chipHeight, -1);
if (mChipHeight == -1) {
mChipHeight = r.getDimension(R.dimen.chip_height);
}
mChipFontSize = a.getDimensionPixelSize(R.styleable.RecipientEditTextView_chipFontSize, -1);
if (mChipFontSize == -1) {
mChipFontSize = r.getDimension(R.dimen.chip_text_size);
}
mAvatarPosition =
a.getInt(R.styleable.RecipientEditTextView_avatarPosition, AVATAR_POSITION_START);
mDisableDelete = a.getBoolean(R.styleable.RecipientEditTextView_disableDelete, false);
mMaxLines = r.getInteger(R.integer.chips_max_lines);
mLineSpacingExtra = r.getDimensionPixelOffset(R.dimen.line_spacing_extra);
TypedValue tv = new TypedValue();
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
mActionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources()
.getDisplayMetrics());
}
a.recycle();
|
void | setChipHeight(int height)
mChipHeight = height;
|
public void | setDropdownChipLayouter(DropdownChipLayouter dropdownChipLayouter)
mDropdownChipLayouter = dropdownChipLayouter;
mDropdownChipLayouter.setDeleteListener(this);
|
void | setMoreItem(android.widget.TextView moreItem)
mMoreItem = moreItem;
|
public void | setOnFocusListShrinkRecipients(boolean shrink)Set whether to shrink the recipients field such that at most
one line of recipients chips are shown when the field loses
focus. By default, the number of displayed recipients will be
limited and a "more" chip will be shown when focus is lost.
mShouldShrink = shrink;
|
public void | setRecipientEntryItemClickedListener(com.android.ex.chips.RecipientEditTextView$RecipientEntryItemClickedListener listener)
mRecipientEntryItemClickedListener = listener;
|
public void | setTokenizer(Tokenizer tokenizer)
mTokenizer = tokenizer;
super.setTokenizer(mTokenizer);
|
public void | setValidator(Validator validator)
mValidator = validator;
super.setValidator(validator);
|
private boolean | shouldCreateChip(int start, int end)
return !mNoChips && hasFocus() && enoughToFilter() && !alreadyHasChip(start, end);
|
private boolean | shouldPositionAvatarOnRight()Returns true if the avatar should be positioned at the right edge of the chip.
Takes into account both the set avatar position (start or end) as well as whether
the layout direction is LTR or RTL.
final boolean isRtl = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ?
getLayoutDirection() == LAYOUT_DIRECTION_RTL : false;
final boolean assignedPosition = mAvatarPosition == AVATAR_POSITION_END;
// If in Rtl mode, the position should be flipped.
return isRtl ? !assignedPosition : assignedPosition;
|
private boolean | shouldShowEditableText(com.android.ex.chips.recipientchip.DrawableRecipientChip currentChip)
long contactId = currentChip.getContactId();
return contactId == RecipientEntry.INVALID_CONTACT
|| (!isPhoneQuery() && contactId == RecipientEntry.GENERATED_CONTACT);
|
private void | showAddress(com.android.ex.chips.recipientchip.DrawableRecipientChip currentChip, android.widget.ListPopupWindow popup)
if (!mAttachedToWindow) {
return;
}
int line = getLayout().getLineForOffset(getChipStart(currentChip));
int bottomOffset = calculateOffsetFromBottomToTop(line);
// Align the alternates popup with the left side of the View,
// regardless of the position of the chip tapped.
popup.setAnchorView((mAlternatePopupAnchor != null) ? mAlternatePopupAnchor : this);
popup.setVerticalOffset(bottomOffset);
popup.setAdapter(createSingleAddressAdapter(currentChip));
popup.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
unselectChip(currentChip);
popup.dismiss();
}
});
popup.show();
ListView listView = popup.getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setItemChecked(0, true);
|
private void | showAlternates(com.android.ex.chips.recipientchip.DrawableRecipientChip currentChip, android.widget.ListPopupWindow alternatesPopup)
new AsyncTask<Void, Void, ListAdapter>() {
@Override
protected ListAdapter doInBackground(final Void... params) {
return createAlternatesAdapter(currentChip);
}
@Override
protected void onPostExecute(final ListAdapter result) {
if (!mAttachedToWindow) {
return;
}
int line = getLayout().getLineForOffset(getChipStart(currentChip));
int bottomOffset = calculateOffsetFromBottomToTop(line);
// Align the alternates popup with the left side of the View,
// regardless of the position of the chip tapped.
alternatesPopup.setAnchorView((mAlternatePopupAnchor != null) ?
mAlternatePopupAnchor : RecipientEditTextView.this);
alternatesPopup.setVerticalOffset(bottomOffset);
alternatesPopup.setAdapter(result);
alternatesPopup.setOnItemClickListener(mAlternatesListener);
// Clear the checked item.
mCheckedItem = -1;
alternatesPopup.show();
ListView listView = alternatesPopup.getListView();
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Checked item would be -1 if the adapter has not
// loaded the view that should be checked yet. The
// variable will be set correctly when onCheckedItemChanged
// is called in a separate thread.
if (mCheckedItem != -1) {
listView.setItemChecked(mCheckedItem, true);
mCheckedItem = -1;
}
}
}.execute((Void[]) null);
|
private void | showCopyDialog(java.lang.String address)
if (!mAttachedToWindow) {
return;
}
mCopyAddress = address;
mCopyDialog.setTitle(address);
mCopyDialog.setContentView(R.layout.copy_chip_dialog_layout);
mCopyDialog.setCancelable(true);
mCopyDialog.setCanceledOnTouchOutside(true);
Button button = (Button)mCopyDialog.findViewById(android.R.id.button1);
button.setOnClickListener(this);
int btnTitleId;
if (isPhoneQuery()) {
btnTitleId = R.string.copy_number;
} else {
btnTitleId = R.string.copy_email;
}
String buttonTitle = getContext().getResources().getString(btnTitleId);
button.setText(buttonTitle);
mCopyDialog.setOnDismissListener(this);
mCopyDialog.show();
|
private void | shrink()
if (mTokenizer == null) {
return;
}
long contactId = mSelectedChip != null ? mSelectedChip.getEntry().getContactId() : -1;
if (mSelectedChip != null && contactId != RecipientEntry.INVALID_CONTACT
&& (!isPhoneQuery() && contactId != RecipientEntry.GENERATED_CONTACT)) {
clearSelectedChip();
} else {
if (getWidth() <= 0) {
// We don't have the width yet which means the view hasn't been drawn yet
// and there is no reason to attempt to commit chips yet.
// This focus lost must be the result of an orientation change
// or an initial rendering.
// Re-post the shrink for later.
mHandler.removeCallbacks(mDelayedShrink);
mHandler.post(mDelayedShrink);
return;
}
// Reset any pending chips as they would have been handled
// when the field lost focus.
if (mPendingChipsCount > 0) {
postHandlePendingChips();
} else {
Editable editable = getText();
int end = getSelectionEnd();
int start = mTokenizer.findTokenStart(editable, end);
DrawableRecipientChip[] chips =
getSpannable().getSpans(start, end, DrawableRecipientChip.class);
if ((chips == null || chips.length == 0)) {
Editable text = getText();
int whatEnd = mTokenizer.findTokenEnd(text, start);
// This token was already tokenized, so skip past the ending token.
if (whatEnd < text.length() && text.charAt(whatEnd) == ',") {
whatEnd = movePastTerminators(whatEnd);
}
// In the middle of chip; treat this as an edit
// and commit the whole token.
int selEnd = getSelectionEnd();
if (whatEnd != selEnd) {
handleEdit(start, whatEnd);
} else {
commitChip(start, end, editable);
}
}
}
mHandler.post(mAddTextWatcher);
}
createMoreChip();
|
private void | startDrag(com.android.ex.chips.recipientchip.DrawableRecipientChip currentChip)Starts drag-and-drop for the selected chip.
String address = currentChip.getEntry().getDestination();
ClipData data = ClipData.newPlainText(address, address + COMMIT_CHAR_COMMA);
// Start drag mode.
startDrag(data, new RecipientChipShadow(currentChip), null, 0);
// Remove the current chip, so drag-and-drop will result in a move.
// TODO (phamm): consider readd this chip if it's dropped outside a target.
removeChip(currentChip);
|
private int | submitItemAtPosition(int position)
RecipientEntry entry = createValidatedEntry(getAdapter().getItem(position));
if (entry == null) {
return -1;
}
clearComposingText();
int end = getSelectionEnd();
int start = mTokenizer.findTokenStart(getText(), end);
Editable editable = getText();
QwertyKeyListener.markAsReplaced(editable, start, end, "");
CharSequence chip = createChip(entry, false);
if (chip != null && start >= 0 && end >= 0) {
editable.replace(start, end, chip);
}
sanitizeBetween();
return end - start;
|
private float | supportConvertToLocalHorizontalCoordinate(float x)
x -= getTotalPaddingLeft();
// Clamp the position to inside of the view.
x = Math.max(0.0f, x);
x = Math.min(getWidth() - getTotalPaddingRight() - 1, x);
x += getScrollX();
return x;
|
private int | supportGetLineAtCoordinate(float y)
y -= getTotalPaddingLeft();
// Clamp the position to inside of the view.
y = Math.max(0.0f, y);
y = Math.min(getHeight() - getTotalPaddingBottom() - 1, y);
y += getScrollY();
return getLayout().getLineForVertical((int) y);
|
private int | supportGetOffsetAtCoordinate(int line, float x)
x = supportConvertToLocalHorizontalCoordinate(x);
return getLayout().getOffsetForHorizontal(line, x);
|
private int | supportGetOffsetForPosition(float x, float y)
if (getLayout() == null) return -1;
final int line = supportGetLineAtCoordinate(y);
final int offset = supportGetOffsetAtCoordinate(line, x);
return offset;
|
private static java.lang.String | tokenizeAddress(java.lang.String destination)
Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(destination);
if (tokens != null && tokens.length > 0) {
return tokens[0].getAddress();
}
return destination;
|
private void | unselectChip(com.android.ex.chips.recipientchip.DrawableRecipientChip chip)Remove selection from this chip. Unselecting a RecipientChip will render
the chip without a delete icon and with an unfocused background. This is
called when the RecipientChip no longer has focus.
int start = getChipStart(chip);
int end = getChipEnd(chip);
Editable editable = getText();
mSelectedChip = null;
if (start == -1 || end == -1) {
Log.w(TAG, "The chip doesn't exist or may be a chip a user was editing");
setSelection(editable.length());
commitDefault();
} else {
getSpannable().removeSpan(chip);
QwertyKeyListener.markAsReplaced(editable, start, end, "");
editable.removeSpan(chip);
try {
if (!mNoChips) {
editable.setSpan(constructChipSpan(chip.getEntry(), false),
start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} catch (NullPointerException e) {
Log.e(TAG, e.getMessage(), e);
}
}
setCursorVisible(true);
setSelection(editable.length());
if (mAlternatesPopup != null && mAlternatesPopup.isShowing()) {
mAlternatesPopup.dismiss();
}
|