EmojiMatcher.java revision 82d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439
182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/* 282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Copyright (C) 2017 The Android Open Source Project 382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License"); 582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * you may not use this file except in compliance with the License. 682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * You may obtain a copy of the License at 782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * http://www.apache.org/licenses/LICENSE-2.0 982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 1082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Unless required by applicable law or agreed to in writing, software 1182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS, 1282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * See the License for the specific language governing permissions and 1482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * limitations under the License. 1582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 1682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirpackage android.support.text.emoji.util; 1782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 1882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.text.emoji.EmojiSpan; 1982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.text.Spanned; 2082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 2182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.hamcrest.Description; 2282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.hamcrest.Matcher; 2382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.hamcrest.TypeSafeMatcher; 2482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 2582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/** 2682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Utility class that includes matchers specific to emojis and EmojiSpans. 2782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 2882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirpublic class EmojiMatcher { 2982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 3082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmojiAt(final int id, final int start, 3182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final int end) { 3282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiResourceMatcher(id, start, end); 3382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 3482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 3582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmojiAt(final Emoji.EmojiMapping emojiMapping, 3682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final int start, final int end) { 3782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiResourceMatcher(emojiMapping.id(), start, end); 3882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 3982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 4082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmojiAt(final int start, final int end) { 4182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiResourceMatcher(-1, start, end); 4282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 4382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 4482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmoji(final int id) { 4582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiResourceMatcher(id, -1, -1); 4682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 4782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 4882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmoji(final Emoji.EmojiMapping emojiMapping) { 4982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiResourceMatcher(emojiMapping.id(), -1, -1); 5082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 5182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 5282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmoji() { 5382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiSpanMatcher(); 5482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 5582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 5682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static Matcher<CharSequence> hasEmojiCount(final int count) { 5782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new EmojiCountMatcher(count); 5882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 5982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static class EmojiSpanMatcher extends TypeSafeMatcher<CharSequence> { 6282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private EmojiSpan[] mSpans; 6482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir EmojiSpanMatcher() { 6682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 6782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 6982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public void describeTo(Description description) { 7082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir description.appendText("should have EmojiSpans"); 7182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 7282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 7382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 7482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir protected void describeMismatchSafely(final CharSequence charSequence, 7582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Description mismatchDescription) { 7682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" has no EmojiSpans"); 7782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 7882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 7982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 8082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir protected boolean matchesSafely(final CharSequence charSequence) { 8182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (charSequence == null) return false; 8282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (!(charSequence instanceof Spanned)) return false; 8382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class); 8482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mSpans.length != 0; 8582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 8682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 8782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 8882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static class EmojiCountMatcher extends TypeSafeMatcher<CharSequence> { 8982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 9082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final int mCount; 9182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private EmojiSpan[] mSpans; 9282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 9382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir EmojiCountMatcher(final int count) { 9482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mCount = count; 9582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 9682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 9782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 9882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public void describeTo(Description description) { 9982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir description.appendText("should have ").appendValue(mCount).appendText(" EmojiSpans"); 10082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 10182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 10282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 10382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir protected void describeMismatchSafely(final CharSequence charSequence, 10482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Description mismatchDescription) { 10582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" has "); 10682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mSpans == null) { 10782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendValue("no"); 10882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } else { 10982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendValue(mSpans.length); 11082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 11182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 11282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" EmojiSpans"); 11382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 11482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 11582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 11682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir protected boolean matchesSafely(final CharSequence charSequence) { 11782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (charSequence == null) return false; 11882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (!(charSequence instanceof Spanned)) return false; 11982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class); 12082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mSpans.length == mCount; 12182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 12282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 12382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 12482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static class EmojiResourceMatcher extends TypeSafeMatcher<CharSequence> { 12582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static final int ERR_NONE = 0; 12682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static final int ERR_SPANNABLE_NULL = 1; 12782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static final int ERR_NO_SPANS = 2; 12882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static final int ERR_WRONG_INDEX = 3; 12982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final int mResId; 13082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final int mStart; 13182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final int mEnd; 13282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private int mError = ERR_NONE; 13382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private int mActualStart = -1; 13482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private int mActualEnd = -1; 13582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 13682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir EmojiResourceMatcher(int resId, int start, int end) { 13782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mResId = resId; 13882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mStart = start; 13982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mEnd = end; 14082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 14182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 14282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 14382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public void describeTo(final Description description) { 14482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mResId == -1) { 14582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir description.appendText("should have EmojiSpan at ") 14682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir .appendValue("[" + mStart + "," + mEnd + "]"); 14782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } else if (mStart == -1 && mEnd == -1) { 14882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir description.appendText("should have EmojiSpan with resource id ") 14982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir .appendValue(Integer.toHexString(mResId)); 15082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } else { 15182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir description.appendText("should have EmojiSpan with resource id ") 15282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir .appendValue(Integer.toHexString(mResId)) 15382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir .appendText(" at ") 15482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir .appendValue("[" + mStart + "," + mEnd + "]"); 15582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 15682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 15782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 15882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 15982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir protected void describeMismatchSafely(final CharSequence charSequence, 16082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Description mismatchDescription) { 16182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir int offset = 0; 16282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText("["); 16382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir while (offset < charSequence.length()) { 16482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir int codepoint = Character.codePointAt(charSequence, offset); 16582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(Integer.toHexString(codepoint)); 16682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir offset += Character.charCount(codepoint); 16782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (offset < charSequence.length()) { 16882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(","); 16982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 17082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 17182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText("]"); 17282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 17382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir switch (mError) { 17482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir case ERR_NO_SPANS: 17582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" had no spans"); 17682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir break; 17782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir case ERR_SPANNABLE_NULL: 17882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" was null"); 17982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir break; 18082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir case ERR_WRONG_INDEX: 18182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" had Emoji at ") 18282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir .appendValue("[" + mActualStart + "," + mActualEnd + "]"); 18382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir break; 18482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir default: 18582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mismatchDescription.appendText(" does not have an EmojiSpan with given " 18682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir + "resource id "); 18782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 18882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 18982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 19082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @Override 19182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir protected boolean matchesSafely(final CharSequence charSequence) { 19282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (charSequence == null) { 19382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mError = ERR_SPANNABLE_NULL; 19482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return false; 19582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 19682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 19782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (!(charSequence instanceof Spanned)) { 19882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mError = ERR_NO_SPANS; 19982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return false; 20082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 20182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 20282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Spanned spanned = (Spanned) charSequence; 20382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class); 20482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 20582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (spans.length == 0) { 20682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mError = ERR_NO_SPANS; 20782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return false; 20882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 20982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 21082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mStart == -1 && mEnd == -1) { 21182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir for (int index = 0; index < spans.length; index++) { 21282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mResId == spans[index].getId()) { 21382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return true; 21482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 21582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 21682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return false; 21782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } else { 21882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir for (int index = 0; index < spans.length; index++) { 21982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mResId == -1 || mResId == spans[index].getId()) { 22082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mActualStart = spanned.getSpanStart(spans[index]); 22182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mActualEnd = spanned.getSpanEnd(spans[index]); 22282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mActualStart == mStart && mActualEnd == mEnd) { 22382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return true; 22482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 22582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 22682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 22782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 22882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mActualStart != -1 && mActualEnd != -1) { 22982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mError = ERR_WRONG_INDEX; 23082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 23282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return false; 23382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir} 237