Java Code Examples for android.text.SpannableString#length()

The following examples show how to use android.text.SpannableString#length() . 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: CCPActivityBase.java    From browser with GNU General Public License v2.0 6 votes vote down vote up
/**
 *
 */
protected SpannableString buildActionTitle() {
    int dimensionPixelSize = mActionBarActivity.getResources().getDimensionPixelSize(R.dimen.BigTextSize);

    int mutIndex = 0;
    String format = "%s";
    if(isMute) {
        format = format + " #";
        mutIndex += 2;
    }

    SpannableString spannableString = new SpannableString(mTitleText);
    //EmoticonUtil.getTextFormat(mActionBarActivity, String.format(format, new Object[]{mTitleText}), dimensionPixelSize);
    if(isMute) {
        if(mMuteIcon == null) {
            mMuteIcon = getTitleIconTips(dimensionPixelSize, R.drawable.chat_mute_notify_title_icon);
        }
        int length = spannableString.length() - mutIndex + 1;
        spannableString.setSpan(mMuteIcon, length, length + 1, SpannableStringBuilder.SPAN_POINT_MARK);
    }
    return spannableString;
}
 
Example 2
Source File: RecipientsEditor.java    From mollyim-android with GNU General Public License v3.0 5 votes vote down vote up
public static CharSequence contactToToken(@NonNull Context context, @NonNull Recipient c) {
  String name       = c.getDisplayName(context);
  String number     = c.getE164().or(c.getEmail()).or("");
  SpannableString s = new SpannableString(RecipientsFormatter.formatNameAndNumber(name, number));
  int len           = s.length();

  if (len == 0) {
    return s;
  }

  s.setSpan(new Annotation("number", number), 0, len,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

  return s;
}
 
Example 3
Source File: RecipientsEditor.java    From bcm-android with GNU General Public License v3.0 5 votes vote down vote up
public static CharSequence contactToToken(Recipient c) {
  String name       = c.getName();
  String number     = c.getAddress().serialize();
  SpannableString s = new SpannableString(RecipientsFormatter.formatNameAndNumber(name, number));
  int len           = s.length();

  if (len == 0) {
    return s;
  }

  s.setSpan(new Annotation("number", c.getAddress().serialize()), 0, len,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

  return s;
}
 
Example 4
Source File: Main.java    From glitchify with MIT License 5 votes vote down vote up
private SpannableStringBuilder injectBadges(XC_MethodHook.MethodHookParam param, Class mediaSpanClass, SpannableStringBuilder chatMsg, Hashtable customBadges) {
    String chatSender = (String) callMethod(param.args[0], "getDisplayName");
    int location = chatMsg.toString().indexOf(chatSender);
    if (location == -1) { return chatMsg; }

    int badgeCount;
    if (location == 0) {
        badgeCount = location;
    } else {
        badgeCount = chatMsg.toString().substring(0, location - 1).split(" ").length;
    }

    for (Object key : customBadges.keySet()) {
        if (badgeCount >= 3) {
            // Already at 3 badges, anymore will clog up chat box
            return chatMsg;
        }
        String keyString = (String) key;
        if (preferences.hiddenBadges().contains(keyString)) {
            continue;
        }
        if (!((ArrayList) ((Hashtable) customBadges.get(keyString)).get("users")).contains(chatSender)) {
            continue;
        }
        String url = (String) ((Hashtable) customBadges.get(keyString)).get("image");
        SpannableString badgeSpan = (SpannableString) callMethod(param.thisObject, "a", param.thisObject, url, Enum.valueOf(mediaSpanClass, "Badge"), keyString + " ", null, true, 8, null);
        chatMsg.insert(location, badgeSpan);
        location += badgeSpan.length();
        badgeCount++;
    }
    return chatMsg;
}
 
Example 5
Source File: RecipientsEditor.java    From Silence with GNU General Public License v3.0 5 votes vote down vote up
public static CharSequence contactToToken(Recipient c) {
  String name       = c.getName();
  String number     = c.getNumber();
  SpannableString s = new SpannableString(RecipientsFormatter.formatNameAndNumber(name, number));
  int len           = s.length();

  if (len == 0) {
    return s;
  }

  s.setSpan(new Annotation("number", c.getNumber()), 0, len,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

  return s;
}
 
Example 6
Source File: LargeAnimatedTextView.java    From tilt-game-android with MIT License 5 votes vote down vote up
@Override
public void setText(CharSequence text, BufferType type) {
	_newText = new SpannableString(text);
	TextChar[] letters = _newText.getSpans(0, _newText.length(), TextChar.class);

	for (TextChar letter : letters) {
		_newText.removeSpan(letter);
	}
	for (int i = 0; i < _newText.length(); i++) {
		_newText.setSpan(new TextChar(getTextSize()), i, i + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
	}

	super.setText(_newText, BufferType.SPANNABLE);
}
 
Example 7
Source File: FaceConversionUtil.java    From weixin with Apache License 2.0 5 votes vote down vote up
/**
 * 对spanableString进行正则判断,如果符合要求,则以表情图片代替
 * 
 * @param context 上下文
 * @param spannableString 一个SpannableString对象
 * @param patten 一个Pattern对象(正则)
 * @param start 起始位置
 * @throws Exception
 */
private void dealExpression(Context context, SpannableString spannableString, Pattern patten, int start) throws Exception {
	Matcher matcher = patten.matcher(spannableString);
	while (matcher.find()) {//尝试查找与该模式匹配的输入序列的下一个子序列
		String key = matcher.group();//返回由以前匹配操作所匹配的输入子序列
		// 返回第一个字符的索引的文本匹配整个正则表达式,ture 则继续递归
		if (matcher.start() < start) {//返回以前匹配的初始索引
			continue;
		}
		String value = mMap_emoji.get(key);
		if (TextUtils.isEmpty(value)) {
			continue;
		}
		int resId = context.getResources().getIdentifier(value, "drawable", context.getPackageName());
		// 通过上面匹配得到的字符串来生成图片资源id
		// Field field=R.drawable.class.getDeclaredField(value);
		// int resId=Integer.parseInt(field.get(null).toString());
		if (resId != 0) {
			Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
			bitmap = Bitmap.createScaledBitmap(bitmap, DensityUtil.dip2px(context, 48), DensityUtil.dip2px(context, 48), true);
			// 通过图片资源id来得到bitmap,用一个ImageSpan来包装
			ImageSpan imageSpan = new ImageSpan(bitmap);
			// 计算该图片名字的长度,也就是要替换的字符串的长度
			int end = matcher.start() + key.length();
			// 将该图片替换字符串中规定的位置中
			spannableString.setSpan(imageSpan, matcher.start(), end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
			if (end < spannableString.length()) {
				// 如果整个字符串还未验证完,则继续。。
				dealExpression(context, spannableString, patten, end);
			}
			break;
		}
	}
}
 
Example 8
Source File: RecipientsAdapter.java    From mollyim-android with GNU General Public License v3.0 4 votes vote down vote up
@Override
public final CharSequence convertToString(Cursor cursor) {
    String name = cursor.getString(RecipientsAdapter.NAME_INDEX);
    int type = cursor.getInt(RecipientsAdapter.TYPE_INDEX);
    String number = cursor.getString(RecipientsAdapter.NUMBER_INDEX).trim();

    String label = cursor.getString(RecipientsAdapter.LABEL_INDEX);
    CharSequence displayLabel = mContactAccessor.phoneTypeToString(mContext, type, label);

    if (number.length() == 0) {
        return number;
    }

    if (name == null) {
        name = "";
    } else {
        // Names with commas are the bane of the recipient editor's existence.
        // We've worked around them by using spans, but there are edge cases
        // where the spans get deleted. Furthermore, having commas in names
        // can be confusing to the user since commas are used as separators
        // between recipients. The best solution is to simply remove commas
        // from names.
        name = name.replace(", ", " ")
                   .replace(",", " ");  // Make sure we leave a space between parts of names.
    }

    String nameAndNumber = RecipientsFormatter.formatNameAndNumber(name, number);

    SpannableString out = new SpannableString(nameAndNumber);
    int len = out.length();

    if (!TextUtils.isEmpty(name)) {
        out.setSpan(new Annotation("name", name), 0, len,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    } else {
        out.setSpan(new Annotation("name", number), 0, len,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    String person_id = cursor.getString(RecipientsAdapter.CONTACT_ID_INDEX);
    out.setSpan(new Annotation("person_id", person_id), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    out.setSpan(new Annotation("label", displayLabel.toString()), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);              
    out.setSpan(new Annotation("number", number), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    return out;
}
 
Example 9
Source File: InputLogic.java    From openboard with GNU General Public License v3.0 4 votes vote down vote up
/**
 * Reverts a previous commit with auto-correction.
 *
 * This is triggered upon pressing backspace just after a commit with auto-correction.
 *
 * @param inputTransaction The transaction in progress.
 * @param settingsValues the current values of the settings.
 */
private void revertCommit(final InputTransaction inputTransaction,
        final SettingsValues settingsValues) {
    final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord;
    final String originallyTypedWordString =
            originallyTypedWord != null ? originallyTypedWord.toString() : "";
    final CharSequence committedWord = mLastComposedWord.mCommittedWord;
    final String committedWordString = committedWord.toString();
    final int cancelLength = committedWord.length();
    final String separatorString = mLastComposedWord.mSeparatorString;
    // If our separator is a space, we won't actually commit it,
    // but set the space state to PHANTOM so that a space will be inserted
    // on the next keypress
    final boolean usePhantomSpace = separatorString.equals(Constants.STRING_SPACE);
    // We want java chars, not codepoints for the following.
    final int separatorLength = separatorString.length();
    // TODO: should we check our saved separator against the actual contents of the text view?
    final int deleteLength = cancelLength + separatorLength;
    if (DebugFlags.DEBUG_ENABLED) {
        if (mWordComposer.isComposingWord()) {
            throw new RuntimeException("revertCommit, but we are composing a word");
        }
        final CharSequence wordBeforeCursor =
                mConnection.getTextBeforeCursor(deleteLength, 0).subSequence(0, cancelLength);
        if (!TextUtils.equals(committedWord, wordBeforeCursor)) {
            throw new RuntimeException("revertCommit check failed: we thought we were "
                    + "reverting \"" + committedWord
                    + "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
        }
    }
    mConnection.deleteTextBeforeCursor(deleteLength);
    if (!TextUtils.isEmpty(committedWord)) {
        unlearnWord(committedWordString, inputTransaction.getMSettingsValues(),
                Constants.EVENT_REVERT);
    }
    final String stringToCommit = originallyTypedWord +
            (usePhantomSpace ? "" : separatorString);
    final SpannableString textToCommit = new SpannableString(stringToCommit);
    if (committedWord instanceof SpannableString) {
        final SpannableString committedWordWithSuggestionSpans = (SpannableString)committedWord;
        final Object[] spans = committedWordWithSuggestionSpans.getSpans(0,
                committedWord.length(), Object.class);
        final int lastCharIndex = textToCommit.length() - 1;
        // We will collect all suggestions in the following array.
        final ArrayList<String> suggestions = new ArrayList<>();
        // First, add the committed word to the list of suggestions.
        suggestions.add(committedWordString);
        for (final Object span : spans) {
            // If this is a suggestion span, we check that the word is not the committed word.
            // That should mostly be the case.
            // Given this, we add it to the list of suggestions, otherwise we discard it.
            if (span instanceof SuggestionSpan) {
                final SuggestionSpan suggestionSpan = (SuggestionSpan)span;
                for (final String suggestion : suggestionSpan.getSuggestions()) {
                    if (!suggestion.equals(committedWordString)) {
                        suggestions.add(suggestion);
                    }
                }
            } else {
                // If this is not a suggestion span, we just add it as is.
                textToCommit.setSpan(span, 0 /* start */, lastCharIndex /* end */,
                        committedWordWithSuggestionSpans.getSpanFlags(span));
            }
        }
        // Add the suggestion list to the list of suggestions.
        textToCommit.setSpan(new SuggestionSpan(mLatinIME /* context */,
                inputTransaction.getMSettingsValues().mLocale,
                suggestions.toArray(new String[suggestions.size()]), 0 /* flags */,
                null /* notificationTargetClass */),
                0 /* start */, lastCharIndex /* end */, 0 /* flags */);
    }

    if (inputTransaction.getMSettingsValues().mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
        mConnection.commitText(textToCommit, 1);
        if (usePhantomSpace) {
            mSpaceState = SpaceState.PHANTOM;
        }
    } else {
        // For languages without spaces, we revert the typed string but the cursor is flush
        // with the typed word, so we need to resume suggestions right away.
        final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
        mWordComposer.setComposingWord(codePoints,
                mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
        setComposingTextInternal(textToCommit, 1);
    }
    // Don't restart suggestion yet. We'll restart if the user deletes the separator.
    mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;

    // We have a separator between the word and the cursor: we should show predictions.
    inputTransaction.setRequiresUpdateSuggestions();
}
 
Example 10
Source File: MessageListItem.java    From zom-android-matrix with Apache License 2.0 4 votes vote down vote up
private CharSequence formatPresenceUpdates(String contact, int type, Date date, boolean isGroupChat,
        boolean scrolling) {
    String body;

    Resources resources =getResources();

    switch (type) {
    case Imps.MessageType.PRESENCE_AVAILABLE:
        body = resources.getString(isGroupChat ? R.string.contact_joined
                                               : R.string.contact_online, contact);
        break;

    case Imps.MessageType.PRESENCE_AWAY:
        body = resources.getString(R.string.contact_away, contact);
        break;

    case Imps.MessageType.PRESENCE_DND:
        body = resources.getString(R.string.contact_busy, contact);
        break;

    case Imps.MessageType.PRESENCE_UNAVAILABLE:
        body = resources.getString(isGroupChat ? R.string.contact_left
                                               : R.string.contact_offline, contact);
        break;

    default:
        return null;
    }

    body += " - ";
    body += formatTimeStamp(date,type, null, EncryptionState.NONE, null);

    if (scrolling) {
        return body;
    } else {
        SpannableString spanText = new SpannableString(body);
        int len = spanText.length();
        spanText.setSpan(new StyleSpan(Typeface.ITALIC), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        spanText.setSpan(new RelativeSizeSpan((float) 0.8), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return spanText;
    }
}
 
Example 11
Source File: FloatingLabelSpinner.java    From FloatingLabelSpinner with Apache License 2.0 4 votes vote down vote up
private void drawSpannableString(final Canvas canvas, CharSequence hint, final TextPaint paint, final int start_x, final int start_y) {
    // draw each span one at a time
    int next;
    float xStart = start_x;
    float xEnd;

    if (paint != errorPaint)
        hint = TextUtils.ellipsize(hint, paint, getWidth() - padding_left - padding_right - label_horizontal_margin, TextUtils.TruncateAt.END);

    if (hint instanceof SpannableString) {
        SpannableString spannableString = (SpannableString) hint;
        for (int i = 0; i < spannableString.length(); i = next) {

            // find the next span transition
            next = spannableString.nextSpanTransition(i, spannableString.length(), CharacterStyle.class);

            // measure the length of the span
            xEnd = xStart + paint.measureText(spannableString, i, next);

            // draw the highlight (background color) first
            BackgroundColorSpan[] bgSpans = spannableString.getSpans(i, next, BackgroundColorSpan.class);
            if (bgSpans.length > 0) {
                Paint mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
                mHighlightPaint.setColor(bgSpans[0].getBackgroundColor());
                canvas.drawRect(xStart, start_y + paint.getFontMetrics().top, xEnd, start_y + paint.getFontMetrics().bottom, mHighlightPaint);
            }

            // draw the text with an optional foreground color
            ForegroundColorSpan[] fgSpans = spannableString.getSpans(i, next, ForegroundColorSpan.class);
            if (fgSpans.length > 0) {
                int saveColor = paint.getColor();
                paint.setColor(fgSpans[0].getForegroundColor());
                canvas.drawText(spannableString, i, next, xStart, start_y, paint);
                paint.setColor(saveColor);
            } else {
                canvas.drawText(spannableString, i, next, xStart, start_y, paint);
            }

            xStart = xEnd;
        }
    } else {
        canvas.drawText(hint, 0, hint.length(), xStart, start_y, paint);
    }

}
 
Example 12
Source File: InputLogic.java    From AOSP-Kayboard-7.1.2 with Apache License 2.0 4 votes vote down vote up
/**
 * Reverts a previous commit with auto-correction.
 *
 * This is triggered upon pressing backspace just after a commit with auto-correction.
 *
 * @param inputTransaction The transaction in progress.
 * @param settingsValues the current values of the settings.
 */
private void revertCommit(final InputTransaction inputTransaction,
        final SettingsValues settingsValues) {
    final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord;
    final String originallyTypedWordString =
            originallyTypedWord != null ? originallyTypedWord.toString() : "";
    final CharSequence committedWord = mLastComposedWord.mCommittedWord;
    final String committedWordString = committedWord.toString();
    final int cancelLength = committedWord.length();
    final String separatorString = mLastComposedWord.mSeparatorString;
    // If our separator is a space, we won't actually commit it,
    // but set the space state to PHANTOM so that a space will be inserted
    // on the next keypress
    final boolean usePhantomSpace = separatorString.equals(Constants.STRING_SPACE);
    // We want java chars, not codepoints for the following.
    final int separatorLength = separatorString.length();
    // TODO: should we check our saved separator against the actual contents of the text view?
    final int deleteLength = cancelLength + separatorLength;
    if (DebugFlags.DEBUG_ENABLED) {
        if (mWordComposer.isComposingWord()) {
            throw new RuntimeException("revertCommit, but we are composing a word");
        }
        final CharSequence wordBeforeCursor =
                mConnection.getTextBeforeCursor(deleteLength, 0).subSequence(0, cancelLength);
        if (!TextUtils.equals(committedWord, wordBeforeCursor)) {
            throw new RuntimeException("revertCommit check failed: we thought we were "
                    + "reverting \"" + committedWord
                    + "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
        }
    }
    mConnection.deleteTextBeforeCursor(deleteLength);
    if (!TextUtils.isEmpty(committedWord)) {
        unlearnWord(committedWordString, inputTransaction.mSettingsValues,
                Constants.EVENT_REVERT);
    }
    final String stringToCommit = originallyTypedWord +
            (usePhantomSpace ? "" : separatorString);
    final SpannableString textToCommit = new SpannableString(stringToCommit);
    if (committedWord instanceof SpannableString) {
        final SpannableString committedWordWithSuggestionSpans = (SpannableString)committedWord;
        final Object[] spans = committedWordWithSuggestionSpans.getSpans(0,
                committedWord.length(), Object.class);
        final int lastCharIndex = textToCommit.length() - 1;
        // We will collect all suggestions in the following array.
        final ArrayList<String> suggestions = new ArrayList<>();
        // First, add the committed word to the list of suggestions.
        suggestions.add(committedWordString);
        for (final Object span : spans) {
            // If this is a suggestion span, we check that the word is not the committed word.
            // That should mostly be the case.
            // Given this, we add it to the list of suggestions, otherwise we discard it.
            if (span instanceof SuggestionSpan) {
                final SuggestionSpan suggestionSpan = (SuggestionSpan)span;
                for (final String suggestion : suggestionSpan.getSuggestions()) {
                    if (!suggestion.equals(committedWordString)) {
                        suggestions.add(suggestion);
                    }
                }
            } else {
                // If this is not a suggestion span, we just add it as is.
                textToCommit.setSpan(span, 0 /* start */, lastCharIndex /* end */,
                        committedWordWithSuggestionSpans.getSpanFlags(span));
            }
        }
        // Add the suggestion list to the list of suggestions.
        textToCommit.setSpan(new SuggestionSpan(mLatinIME /* context */,
                inputTransaction.mSettingsValues.mLocale,
                suggestions.toArray(new String[suggestions.size()]), 0 /* flags */,
                null /* notificationTargetClass */),
                0 /* start */, lastCharIndex /* end */, 0 /* flags */);
    }

    if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
        mConnection.commitText(textToCommit, 1);
        if (usePhantomSpace) {
            mSpaceState = SpaceState.PHANTOM;
        }
    } else {
        // For languages without spaces, we revert the typed string but the cursor is flush
        // with the typed word, so we need to resume suggestions right away.
        final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
        mWordComposer.setComposingWord(codePoints,
                mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
        setComposingTextInternal(textToCommit, 1);
    }
    // Don't restart suggestion yet. We'll restart if the user deletes the separator.
    mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;

    // We have a separator between the word and the cursor: we should show predictions.
    inputTransaction.setRequiresUpdateSuggestions();
}
 
Example 13
Source File: MessageListItem.java    From Zom-Android-XMPP with GNU General Public License v3.0 4 votes vote down vote up
private CharSequence formatPresenceUpdates(String contact, int type, Date date, boolean isGroupChat,
        boolean scrolling) {
    String body;

    Resources resources =getResources();

    switch (type) {
    case Imps.MessageType.PRESENCE_AVAILABLE:
        body = resources.getString(isGroupChat ? R.string.contact_joined
                                               : R.string.contact_online, contact);
        break;

    case Imps.MessageType.PRESENCE_AWAY:
        body = resources.getString(R.string.contact_away, contact);
        break;

    case Imps.MessageType.PRESENCE_DND:
        body = resources.getString(R.string.contact_busy, contact);
        break;

    case Imps.MessageType.PRESENCE_UNAVAILABLE:
        body = resources.getString(isGroupChat ? R.string.contact_left
                                               : R.string.contact_offline, contact);
        break;

    default:
        return null;
    }

    body += " - ";
    body += formatTimeStamp(date,type, null, EncryptionState.NONE, null);

    if (scrolling) {
        return body;
    } else {
        SpannableString spanText = new SpannableString(body);
        int len = spanText.length();
        spanText.setSpan(new StyleSpan(Typeface.ITALIC), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        spanText.setSpan(new RelativeSizeSpan((float) 0.8), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        return spanText;
    }
}
 
Example 14
Source File: RecipientsAdapter.java    From Silence with GNU General Public License v3.0 4 votes vote down vote up
@Override
public final CharSequence convertToString(Cursor cursor) {
    String name = cursor.getString(RecipientsAdapter.NAME_INDEX);
    int type = cursor.getInt(RecipientsAdapter.TYPE_INDEX);
    String number = cursor.getString(RecipientsAdapter.NUMBER_INDEX).trim();

    String label = cursor.getString(RecipientsAdapter.LABEL_INDEX);
    CharSequence displayLabel = mContactAccessor.phoneTypeToString(mContext, type, label);

    if (number.length() == 0) {
        return number;
    }

    if (name == null) {
        name = "";
    } else {
        // Names with commas are the bane of the recipient editor's existence.
        // We've worked around them by using spans, but there are edge cases
        // where the spans get deleted. Furthermore, having commas in names
        // can be confusing to the user since commas are used as separators
        // between recipients. The best solution is to simply remove commas
        // from names.
        name = name.replace(", ", " ")
                   .replace(",", " ");  // Make sure we leave a space between parts of names.
    }

    String nameAndNumber = RecipientsFormatter.formatNameAndNumber(name, number);

    SpannableString out = new SpannableString(nameAndNumber);
    int len = out.length();

    if (!TextUtils.isEmpty(name)) {
        out.setSpan(new Annotation("name", name), 0, len,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    } else {
        out.setSpan(new Annotation("name", number), 0, len,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    String person_id = cursor.getString(RecipientsAdapter.CONTACT_ID_INDEX);
    out.setSpan(new Annotation("person_id", person_id), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    out.setSpan(new Annotation("label", displayLabel.toString()), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    out.setSpan(new Annotation("number", number), 0, len,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

    return out;
}
 
Example 15
Source File: InputLogic.java    From Indic-Keyboard with Apache License 2.0 4 votes vote down vote up
/**
 * Reverts a previous commit with auto-correction.
 *
 * This is triggered upon pressing backspace just after a commit with auto-correction.
 *
 * @param inputTransaction The transaction in progress.
 * @param settingsValues the current values of the settings.
 */
private void revertCommit(final InputTransaction inputTransaction,
        final SettingsValues settingsValues) {
    Log.d("IndicKeyboard", "InputLogidc: revertCommit");
    final CharSequence originallyTypedWord = mLastComposedWord.mTypedWord;
    final String originallyTypedWordString =
            originallyTypedWord != null ? originallyTypedWord.toString() : "";
    final CharSequence committedWord = mLastComposedWord.mCommittedWord;
    final String committedWordString = committedWord.toString();
    final int cancelLength = committedWord.length();
    final String separatorString = mLastComposedWord.mSeparatorString;
    // If our separator is a space, we won't actually commit it,
    // but set the space state to PHANTOM so that a space will be inserted
    // on the next keypress
    final boolean usePhantomSpace = separatorString.equals(Constants.STRING_SPACE);
    // We want java chars, not codepoints for the following.
    final int separatorLength = separatorString.length();
    // TODO: should we check our saved separator against the actual contents of the text view?
    final int deleteLength = cancelLength + separatorLength;
    if (DebugFlags.DEBUG_ENABLED) {
        if (mWordComposer.isComposingWord()) {
            throw new RuntimeException("revertCommit, but we are composing a word");
        }
        final CharSequence wordBeforeCursor =
                mConnection.getTextBeforeCursor(deleteLength, 0).subSequence(0, cancelLength);
        if (!TextUtils.equals(committedWord, wordBeforeCursor)) {
            throw new RuntimeException("revertCommit check failed: we thought we were "
                    + "reverting \"" + committedWord
                    + "\", but before the cursor we found \"" + wordBeforeCursor + "\"");
        }
    }
    mConnection.deleteTextBeforeCursor(deleteLength);
    if (!TextUtils.isEmpty(committedWord)) {
        unlearnWord(committedWordString, inputTransaction.mSettingsValues,
                Constants.EVENT_REVERT);
    }
    final String stringToCommit = originallyTypedWord +
            (usePhantomSpace ? "" : separatorString);
    final SpannableString textToCommit = new SpannableString(stringToCommit);
    if (committedWord instanceof SpannableString) {
        final SpannableString committedWordWithSuggestionSpans = (SpannableString)committedWord;
        final Object[] spans = committedWordWithSuggestionSpans.getSpans(0,
                committedWord.length(), Object.class);
        final int lastCharIndex = textToCommit.length() - 1;
        // We will collect all suggestions in the following array.
        final ArrayList<String> suggestions = new ArrayList<>();
        // First, add the committed word to the list of suggestions.
        suggestions.add(committedWordString);
        for (final Object span : spans) {
            // If this is a suggestion span, we check that the word is not the committed word.
            // That should mostly be the case.
            // Given this, we add it to the list of suggestions, otherwise we discard it.
            if (span instanceof SuggestionSpan) {
                final SuggestionSpan suggestionSpan = (SuggestionSpan)span;
                for (final String suggestion : suggestionSpan.getSuggestions()) {
                    if (!suggestion.equals(committedWordString)) {
                        suggestions.add(suggestion);
                    }
                }
            } else {
                // If this is not a suggestion span, we just add it as is.
                textToCommit.setSpan(span, 0 /* start */, lastCharIndex /* end */,
                        committedWordWithSuggestionSpans.getSpanFlags(span));
            }
        }
        // Add the suggestion list to the list of suggestions.
        textToCommit.setSpan(new SuggestionSpan(mLatinIME /* context */,
                inputTransaction.mSettingsValues.mLocale,
                suggestions.toArray(new String[suggestions.size()]), 0 /* flags */,
                null /* notificationTargetClass */),
                0 /* start */, lastCharIndex /* end */, 0 /* flags */);
    }

    if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
        mConnection.commitText(textToCommit, 1);
        if (usePhantomSpace) {
            mSpaceState = SpaceState.PHANTOM;
        }
    } else {
        // For languages without spaces, we revert the typed string but the cursor is flush
        // with the typed word, so we need to resume suggestions right away.
        final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
        mWordComposer.setComposingWord(codePoints,
                mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
        setComposingTextInternal(textToCommit, 1);
    }
    // Don't restart suggestion yet. We'll restart if the user deletes the separator.
    mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;

    // We have a separator between the word and the cursor: we should show predictions.
    inputTransaction.setRequiresUpdateSuggestions();
}