Java Code Examples for android.text.Spannable#getSpanStart()

The following examples show how to use android.text.Spannable#getSpanStart() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: SpannableStringHelper.java    From revolution-irc with GNU General Public License v3.0 6 votes vote down vote up
public static void setAndMergeSpans(Spannable text, Object what, int start, int end, int flags) {
    Object[] spans = text.getSpans(Math.max(start - 1, 0), Math.min(end + 1, 0), what.getClass());
    for (Object span : spans) {
        if (!areSpansEqual(span, what))
            continue;
        int sFlags = text.getSpanFlags(span);
        if ((sFlags & Spanned.SPAN_COMPOSING) != 0)
            continue;

        int sStart = text.getSpanStart(span);
        int sEnd = text.getSpanEnd(span);
        if (sEnd < start || sStart > end)
            continue;
        text.removeSpan(span);
        if (sStart < start)
            start = sStart;
        if (sEnd > end)
            end = sEnd;
    }
    text.setSpan(what, start, end, flags);
}
 
Example 2
Source File: ParagraphSpanProcessor.java    From memoir with Apache License 2.0 6 votes vote down vote up
void process(Spannable str) {
    for (ParagraphSpan paragraphSpan : mParagraphSpans) {
        RTParagraphSpan<V> span = paragraphSpan.mSpan;
        int paraStart = paragraphSpan.mParagraph.start();

        if (paragraphSpan.mRemove) {
            int spanStart = str.getSpanStart(span);
            if (spanStart > -1  && spanStart < paraStart) {
                // process preceding spans
                str.setSpan(span.createClone(), spanStart, paraStart, Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
            }

            str.removeSpan(span);
        }

        else {
            Paragraph paragraph = paragraphSpan.mParagraph;
            int paraEnd = paragraphSpan.mParagraph.end();
            int flags = paragraph.isLast() && paragraph.isEmpty() ? Spanned.SPAN_INCLUSIVE_INCLUSIVE :
                        paragraph.isLast() && paragraph.isFirst() ? Spanned.SPAN_INCLUSIVE_INCLUSIVE :
                        paragraph.isLast() ? Spanned.SPAN_EXCLUSIVE_INCLUSIVE :
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
            str.setSpan(span, paraStart, paraEnd, flags);
        }
    }
}
 
Example 3
Source File: SmileUtils.java    From school_shop with MIT License 6 votes vote down vote up
/**
 * replace existing spannable with smiles
 * @param context
 * @param spannable
 * @return
 */
public static boolean addSmiles(Context context, Spannable spannable) {
    boolean hasChanges = false;
    for (Entry<Pattern, Integer> entry : emoticons.entrySet()) {
        Matcher matcher = entry.getKey().matcher(spannable);
        while (matcher.find()) {
            boolean set = true;
            for (ImageSpan span : spannable.getSpans(matcher.start(),
                    matcher.end(), ImageSpan.class))
                if (spannable.getSpanStart(span) >= matcher.start()
                        && spannable.getSpanEnd(span) <= matcher.end())
                    spannable.removeSpan(span);
                else {
                    set = false;
                    break;
                }
            if (set) {
                hasChanges = true;
                spannable.setSpan(new ImageSpan(context, entry.getValue()),
                        matcher.start(), matcher.end(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }
    return hasChanges;
}
 
Example 4
Source File: CommentTextView.java    From Dashchan with Apache License 2.0 6 votes vote down vote up
private void invalidateSpanToClick() {
	if (spanToClick == null) {
		return;
	}
	CharSequence text = getText();
	if (text instanceof Spannable) {
		Spannable spannable = (Spannable) text;
		int start = spannable.getSpanStart(spanToClick);
		int end = spannable.getSpanEnd(spanToClick);
		if (start >= 0 && end >= start) {
			SpanWatcher[] watchers = spannable.getSpans(0, spannable.length(), SpanWatcher.class);
			if (watchers != null && watchers.length >= 1) {
				for (SpanWatcher watcher : watchers) {
					if (watcher.getClass().getName().equals("android.widget.TextView$ChangeWatcher")) {
						// Notify span changed to redraw it
						watcher.onSpanChanged(spannable, spanToClick, start, end, start, end);
					}
				}
			}
		}
	}
	invalidate();
}
 
Example 5
Source File: EaseSmileUtils.java    From Social with Apache License 2.0 5 votes vote down vote up
/**
 * replace existing spannable with smiles
 * @param context
 * @param spannable
 * @return
 */
public static boolean addSmiles(Context context, Spannable spannable) {
    boolean hasChanges = false;
    for (Entry<Pattern, Object> entry : emoticons.entrySet()) {
        Matcher matcher = entry.getKey().matcher(spannable);
        while (matcher.find()) {
            boolean set = true;
            for (ImageSpan span : spannable.getSpans(matcher.start(),
                    matcher.end(), ImageSpan.class))
                if (spannable.getSpanStart(span) >= matcher.start()
                        && spannable.getSpanEnd(span) <= matcher.end())
                    spannable.removeSpan(span);
                else {
                    set = false;
                    break;
                }
            if (set) {
                hasChanges = true;
                Object value = entry.getValue();
                if(value instanceof String && !((String) value).startsWith("http")){
                    File file = new File((String) value);
                    if(!file.exists() || file.isDirectory()){
                        return false;
                    }
                    spannable.setSpan(new ImageSpan(context, Uri.fromFile(file)),
                            matcher.start(), matcher.end(),
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }else{
                    spannable.setSpan(new ImageSpan(context, (Integer)value),
                            matcher.start(), matcher.end(),
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
        }
    }
    
    return hasChanges;
}
 
Example 6
Source File: PatternsHelper.java    From fanfouapp-opensource with Apache License 2.0 5 votes vote down vote up
public static void removeUnderlines(final TextView textView) {
    final Spannable s = (Spannable) textView.getText();
    final URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
    for (URLSpan span : spans) {
        final int start = s.getSpanStart(span);
        final int end = s.getSpanEnd(span);
        s.removeSpan(span);
        span = new LinkifyCompat.URLSpanNoUnderline(span.getURL());
        s.setSpan(span, start, end, 0);
    }
    textView.setText(s);
}
 
Example 7
Source File: AKHtml.java    From Mupdf with Apache License 2.0 5 votes vote down vote up
private static void setSpanFromMark(Spannable text, Object mark, Object... spans) {
    int where = text.getSpanStart(mark);
    text.removeSpan(mark);
    int len = text.length();
    if (where != len) {
        for (Object span : spans) {
            text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
}
 
Example 8
Source File: StickerManager.java    From Zom-Android-XMPP with GNU General Public License v3.0 5 votes vote down vote up
public boolean addEmoji(Context context, Spannable spannable) throws IOException {
	boolean hasChanges = false;
	for (Entry<Pattern, Sticker> entry : emoticons.entrySet())
	{
		Matcher matcher = entry.getKey().matcher(spannable);
		while (matcher.find()) {
			boolean set = true;
			for (ImageSpan span : spannable.getSpans(matcher.start(),
			        matcher.end(), ImageSpan.class))
				
			    if (spannable.getSpanStart(span) >= matcher.start()
			            && spannable.getSpanEnd(span) <= matcher.end())
			        spannable.removeSpan(span);
			    else {
			        set = false;
			        break;
			    }
			if (set) {
			    hasChanges = true;
			    
			    Sticker emoji = entry.getValue();
			    spannable.setSpan(new ImageSpan(context, BitmapFactory.decodeStream(emoji.res.getAssets().open(emoji.assetUri.getPath()))),
			            matcher.start(), matcher.end(),
			            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
		}
	}
	return hasChanges;
}
 
Example 9
Source File: EaseSmileUtils.java    From nono-android with GNU General Public License v3.0 5 votes vote down vote up
/**
 * replace existing spannable with smiles
 * @param context
 * @param spannable
 * @return
 */
public static boolean addSmiles(Context context, Spannable spannable) {
    boolean hasChanges = false;
    for (Entry<Pattern, Object> entry : emoticons.entrySet()) {
        Matcher matcher = entry.getKey().matcher(spannable);
        while (matcher.find()) {
            boolean set = true;
            for (ImageSpan span : spannable.getSpans(matcher.start(),
                    matcher.end(), ImageSpan.class))
                if (spannable.getSpanStart(span) >= matcher.start()
                        && spannable.getSpanEnd(span) <= matcher.end())
                    spannable.removeSpan(span);
                else {
                    set = false;
                    break;
                }
            if (set) {
                hasChanges = true;
                Object value = entry.getValue();
                if(value instanceof String && !((String) value).startsWith("http")){
                    File file = new File((String) value);
                    if(!file.exists() || file.isDirectory()){
                        return false;
                    }
                    spannable.setSpan(new ImageSpan(context, Uri.fromFile(file)),
                            matcher.start(), matcher.end(),
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }else{
                    spannable.setSpan(new ImageSpan(context, (Integer)value),
                            matcher.start(), matcher.end(),
                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }
        }
    }
    
    return hasChanges;
}
 
Example 10
Source File: QuestionWidget.java    From commcare-android with Apache License 2.0 5 votes vote down vote up
private void stripUnderlines(TextView textView) {
    Spannable s = (Spannable)textView.getText();
    URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
    for (URLSpan span : spans) {
        int start = s.getSpanStart(span);
        int end = s.getSpanEnd(span);
        s.removeSpan(span);
        span = new URLSpanNoUnderline(span.getURL());
        s.setSpan(span, start, end, 0);
    }
    textView.setText(s);
}
 
Example 11
Source File: StickerManager.java    From zom-android-matrix with Apache License 2.0 5 votes vote down vote up
public boolean addEmoji(Context context, Spannable spannable) throws IOException {
	boolean hasChanges = false;
	for (Entry<Pattern, Sticker> entry : emoticons.entrySet())
	{
		Matcher matcher = entry.getKey().matcher(spannable);
		while (matcher.find()) {
			boolean set = true;
			for (ImageSpan span : spannable.getSpans(matcher.start(),
			        matcher.end(), ImageSpan.class))
				
			    if (spannable.getSpanStart(span) >= matcher.start()
			            && spannable.getSpanEnd(span) <= matcher.end())
			        spannable.removeSpan(span);
			    else {
			        set = false;
			        break;
			    }
			if (set) {
			    hasChanges = true;
			    
			    Sticker emoji = entry.getValue();
			    spannable.setSpan(new ImageSpan(context, BitmapFactory.decodeStream(emoji.res.getAssets().open(emoji.assetUri.getPath()))),
			            matcher.start(), matcher.end(),
			            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
		}
	}
	return hasChanges;
}
 
Example 12
Source File: HtmlToSpannedConverter.java    From HtmlCompat with Apache License 2.0 5 votes vote down vote up
private void setSpanFromMark(String tag, Spannable text, Object mark, Object... spans) {
    int where = text.getSpanStart(mark);
    text.removeSpan(mark);
    int len = text.length();
    if (where != len) {
        for (Object span : spans) {
            if (mSpanCallback != null) {
                span = mSpanCallback.onSpanCreated(tag, span);
            }
            text.setSpan(span, where, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
}
 
Example 13
Source File: AccessibilityNodeInfo.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
/**
 * Sets the text of this node.
 * <p>
 *   <strong>Note:</strong> Cannot be called from an
 *   {@link android.accessibilityservice.AccessibilityService}.
 *   This class is made immutable before being delivered to an AccessibilityService.
 * </p>
 *
 * @param text The text.
 *
 * @throws IllegalStateException If called from an AccessibilityService.
 */
public void setText(CharSequence text) {
    enforceNotSealed();
    mOriginalText = text;
    // Replace any ClickableSpans in mText with placeholders
    if (text instanceof Spanned) {
        ClickableSpan[] spans =
                ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
        if (spans.length > 0) {
            Spannable spannable = new SpannableStringBuilder(text);
            for (int i = 0; i < spans.length; i++) {
                ClickableSpan span = spans[i];
                if ((span instanceof AccessibilityClickableSpan)
                        || (span instanceof AccessibilityURLSpan)) {
                    // We've already done enough
                    break;
                }
                int spanToReplaceStart = spannable.getSpanStart(span);
                int spanToReplaceEnd = spannable.getSpanEnd(span);
                int spanToReplaceFlags = spannable.getSpanFlags(span);
                spannable.removeSpan(span);
                ClickableSpan replacementSpan = (span instanceof URLSpan)
                        ? new AccessibilityURLSpan((URLSpan) span)
                        : new AccessibilityClickableSpan(span.getId());
                spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
                        spanToReplaceFlags);
            }
            mText = spannable;
            return;
        }
    }
    mText = (text == null) ? null : text.subSequence(0, text.length());
}
 
Example 14
Source File: RichTextView.java    From YiBo with Apache License 2.0 5 votes vote down vote up
private void stripUnderlines(Spannable s) {
    URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
    for (URLSpan span: spans) {
        int start = s.getSpanStart(span);
        int end = s.getSpanEnd(span);
        s.removeSpan(span);
        span = new URLSpanNoUnderline(span.getURL());
        s.setSpan(span, start, end, 0);
    }
}
 
Example 15
Source File: RuleSpannables.java    From talkback with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a menu item for URLSpan. <strong>Note: </strong> This method will not create menu item
 * for relative URLs.
 */
private @Nullable ContextMenuItem createMenuItemForUrlSpan(
    Context context,
    ContextMenuItemBuilder menuItemBuilder,
    int itemId,
    Spannable spannable,
    URLSpan span) {
  final String url = span.getURL();
  final int start = spannable.getSpanStart(span);
  final int end = spannable.getSpanEnd(span);
  if (start < 0 || end < 0) {
    return null;
  }
  final CharSequence label = spannable.subSequence(start, end);
  if (TextUtils.isEmpty(url) || TextUtils.isEmpty(label)) {
    return null;
  }

  final Uri uri = Uri.parse(url);
  if (uri.isRelative()) {
    // Generally, only absolute URIs are resolvable to an activity
    return null;
  }

  // Strip out ClickableSpans/UrlSpans from the label text.
  // A11y framework has changed how it handles double-tap from O. It's possible that double-tap
  // on the menu item will invoke ClickableSpans in the label text instead of calling
  // MenuItemClickListener. Thus we should remove ClickableSpans from label text.
  // Also apply this rule to pre-O in order to have consistent text appearance.
  SpannableUtils.stripTargetSpanFromText(label, TARGET_SPAN_CLASS);
  final ContextMenuItem item =
      menuItemBuilder.createMenuItem(context, R.id.group_links, itemId, Menu.NONE, label);
  item.setOnMenuItemClickListener(new UrlSpanMenuItemClickListener(context, uri));
  return item;
}
 
Example 16
Source File: LongClickableLinkMovementMethod.java    From iBeebo with GNU General Public License v3.0 4 votes vote down vote up
private boolean action(int what, TextView widget, Spannable buffer) {
    Layout layout = widget.getLayout();

    int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
    int areatop = widget.getScrollY();
    int areabot = areatop + widget.getHeight() - padding;

    int linetop = layout.getLineForVertical(areatop);
    int linebot = layout.getLineForVertical(areabot);

    int first = layout.getLineStart(linetop);
    int last = layout.getLineEnd(linebot);

    MyURLSpan[] candidates = buffer.getSpans(first, last, MyURLSpan.class);

    int a = Selection.getSelectionStart(buffer);
    int b = Selection.getSelectionEnd(buffer);

    int selStart = Math.min(a, b);
    int selEnd = Math.max(a, b);

    if (selStart < 0) {
        if (buffer.getSpanStart(FROM_BELOW) >= 0) {
            selStart = selEnd = buffer.length();
        }
    }

    if (selStart > last) {
        selStart = selEnd = Integer.MAX_VALUE;
    }
    if (selEnd < first) {
        selStart = selEnd = -1;
    }

    switch (what) {
        case CLICK:
            if (selStart == selEnd) {
                return false;
            }

            MyURLSpan[] link = buffer.getSpans(selStart, selEnd, MyURLSpan.class);

            if (link.length != 1) {
                return false;
            }

            link[0].onClick(widget);
            break;

        case UP:
            int best_start = -1;
            int best_end = -1;

            for (MyURLSpan candidate1 : candidates) {
                int end = buffer.getSpanEnd(candidate1);

                if (end < selEnd || selStart == selEnd) {
                    if (end > best_end) {
                        best_start = buffer.getSpanStart(candidate1);
                        best_end = end;
                    }
                }
            }

            if (best_start >= 0) {
                Selection.setSelection(buffer, best_end, best_start);
                return true;
            }

            break;

        case DOWN:
            best_start = Integer.MAX_VALUE;
            best_end = Integer.MAX_VALUE;

            for (MyURLSpan candidate : candidates) {
                int start = buffer.getSpanStart(candidate);

                if (start > selStart || selStart == selEnd) {
                    if (start < best_start) {
                        best_start = start;
                        best_end = buffer.getSpanEnd(candidate);
                    }
                }
            }

            if (best_end < Integer.MAX_VALUE) {
                Selection.setSelection(buffer, best_start, best_end);
                return true;
            }

            break;
    }

    return false;
}
 
Example 17
Source File: CountLinkMovementMethod.java    From timecat with Apache License 2.0 4 votes vote down vote up
private boolean action(int what, TextView widget, Spannable buffer) {
    Layout layout = widget.getLayout();

    int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
    int areatop = widget.getScrollY();
    int areabot = areatop + widget.getHeight() - padding;

    int linetop = layout.getLineForVertical(areatop);
    int linebot = layout.getLineForVertical(areabot);

    int first = layout.getLineStart(linetop);
    int last = layout.getLineEnd(linebot);

    ClickableSpan[] candidates = buffer.getSpans(first, last, ClickableSpan.class);

    int a = Selection.getSelectionStart(buffer);
    int b = Selection.getSelectionEnd(buffer);

    int selStart = Math.min(a, b);
    int selEnd = Math.max(a, b);

    if (selStart < 0) {
        if (buffer.getSpanStart(FROM_BELOW) >= 0) {
            selStart = selEnd = buffer.length();
        }
    }

    if (selStart > last) selStart = selEnd = Integer.MAX_VALUE;
    if (selEnd < first) selStart = selEnd = -1;

    switch (what) {
        case CLICK:
            if (selStart == selEnd) {
                return false;
            }

            ClickableSpan[] link = buffer.getSpans(selStart, selEnd, ClickableSpan.class);

            if (link.length != 1) return false;

            link[0].onClick(widget);
            break;

        case UP:
            int beststart, bestend;

            beststart = -1;
            bestend = -1;

            for (int i = 0; i < candidates.length; i++) {
                int end = buffer.getSpanEnd(candidates[i]);

                if (end < selEnd || selStart == selEnd) {
                    if (end > bestend) {
                        beststart = buffer.getSpanStart(candidates[i]);
                        bestend = end;
                    }
                }
            }

            if (beststart >= 0) {
                Selection.setSelection(buffer, bestend, beststart);
                return true;
            }

            break;

        case DOWN:
            beststart = Integer.MAX_VALUE;
            bestend = Integer.MAX_VALUE;

            for (int i = 0; i < candidates.length; i++) {
                int start = buffer.getSpanStart(candidates[i]);

                if (start > selStart || selStart == selEnd) {
                    if (start < beststart) {
                        beststart = start;
                        bestend = buffer.getSpanEnd(candidates[i]);
                    }
                }
            }

            if (bestend < Integer.MAX_VALUE) {
                Selection.setSelection(buffer, beststart, bestend);
                return true;
            }

            break;
    }

    return false;
}
 
Example 18
Source File: GifProcessor.java    From Markwon with Apache License 2.0 4 votes vote down vote up
@Override
public void process(@NonNull final TextView textView) {

    // here is what we will do additionally:
    // we query for all asyncDrawableSpans
    // we check if they are inside clickableSpan
    // if not we apply onGifListener

    final Spannable spannable = spannable(textView);

    if (spannable == null) {
        return;
    }

    final AsyncDrawableSpan[] asyncDrawableSpans =
            spannable.getSpans(0, spannable.length(), AsyncDrawableSpan.class);
    if (asyncDrawableSpans == null
            || asyncDrawableSpans.length == 0) {
        return;
    }

    int start;
    int end;
    ClickableSpan[] clickableSpans;

    for (final AsyncDrawableSpan asyncDrawableSpan : asyncDrawableSpans) {

        start = spannable.getSpanStart(asyncDrawableSpan);
        end = spannable.getSpanEnd(asyncDrawableSpan);

        if (start < 0
                || end < 0) {
            continue;
        }

        clickableSpans = spannable.getSpans(start, end, ClickableSpan.class);
        if (clickableSpans != null
                && clickableSpans.length > 0) {
            continue;
        }

        ((GifAwareAsyncDrawable) asyncDrawableSpan.getDrawable()).onGifResultListener(new GifAwareAsyncDrawable.OnGifResultListener() {
            @Override
            public void onGifResult(@NonNull GifAwareAsyncDrawable drawable) {
                addGifClickSpan(textView, asyncDrawableSpan, drawable);
            }
        });
    }
}
 
Example 19
Source File: RichEditor.java    From RichEditor with MIT License 4 votes vote down vote up
private <T> void terminateStyle(Spannable spannable, T s) {
    int start = spannable.getSpanStart(s);
    int end = spannable.getSpanEnd(s);
    spannable.removeSpan(s);
    spannable.setSpan(s, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
 
Example 20
Source File: TextChipsEditView.java    From talk-android with MIT License 4 votes vote down vote up
/**
 * 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.
 */
// Visible for testing.
/* package */ void createMoreChip() {
    if (mNoChips) {
        createMoreChipPlainText();
        return;
    }

    if (!mShouldShrink) {
        return;
    }
    ImageSpan[] 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());
    }
}