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 */
16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.emoji.util;
1782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
18f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport static org.mockito.Matchers.argThat;
19f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
2082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.text.Spanned;
21f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.text.TextUtils;
2282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
2338746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.emoji.text.EmojiSpan;
2438746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikas
2582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.hamcrest.Description;
2682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.hamcrest.Matcher;
2782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport org.hamcrest.TypeSafeMatcher;
28963facb8fce35022f296c38fadafd9a959ab1655Aurimas Liutikasimport org.mockito.ArgumentMatcher;
2982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
3082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/**
3182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Utility class that includes matchers specific to emojis and EmojiSpans.
3282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */
3382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirpublic class EmojiMatcher {
3482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
3582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmojiAt(final int id, final int start,
3682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            final int end) {
3782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiResourceMatcher(id, start, end);
3882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
3982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
4082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmojiAt(final Emoji.EmojiMapping emojiMapping,
4182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            final int start, final int end) {
4282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiResourceMatcher(emojiMapping.id(), start, end);
4382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
4482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
4582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmojiAt(final int start, final int end) {
4682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiResourceMatcher(-1, start, end);
4782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
4882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
4982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmoji(final int id) {
5082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiResourceMatcher(id, -1, -1);
5182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
5282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
5382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmoji(final Emoji.EmojiMapping emojiMapping) {
5482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiResourceMatcher(emojiMapping.id(), -1, -1);
5582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
5682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
5782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmoji() {
5882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiSpanMatcher();
5982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
6082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
6182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    public static Matcher<CharSequence> hasEmojiCount(final int count) {
6282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        return new EmojiCountMatcher(count);
6382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
6482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
65f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    public static <T extends CharSequence> T sameCharSequence(final T expected) {
66963facb8fce35022f296c38fadafd9a959ab1655Aurimas Liutikas        return argThat(new ArgumentMatcher<T>() {
67f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir            @Override
68963facb8fce35022f296c38fadafd9a959ab1655Aurimas Liutikas            public boolean matches(T o) {
69410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir                if (o instanceof CharSequence) {
70410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir                    return TextUtils.equals(expected, o);
71f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                }
72f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir                return false;
73f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir            }
74f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir
75f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir            @Override
76963facb8fce35022f296c38fadafd9a959ab1655Aurimas Liutikas            public String toString() {
77963facb8fce35022f296c38fadafd9a959ab1655Aurimas Liutikas                return "doesn't match " + expected;
78f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir            }
79f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir        });
80f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir    }
8182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
8282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    private static class EmojiSpanMatcher extends TypeSafeMatcher<CharSequence> {
8382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
8482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private EmojiSpan[] mSpans;
8582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
8682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        EmojiSpanMatcher() {
8782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
8882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
8982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
9082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        public void describeTo(Description description) {
9182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            description.appendText("should have EmojiSpans");
9282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
9382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
9482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
9582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        protected void describeMismatchSafely(final CharSequence charSequence,
9682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                Description mismatchDescription) {
9782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mismatchDescription.appendText(" has no EmojiSpans");
9882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
9982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
10082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
10182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        protected boolean matchesSafely(final CharSequence charSequence) {
10282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (charSequence == null) return false;
10382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (!(charSequence instanceof Spanned)) return false;
10482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
10582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            return mSpans.length != 0;
10682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
10782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
10882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
10982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    private static class EmojiCountMatcher extends TypeSafeMatcher<CharSequence> {
11082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
11182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private final int mCount;
11282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private EmojiSpan[] mSpans;
11382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
11482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        EmojiCountMatcher(final int count) {
11582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mCount = count;
11682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
11782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
11882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
11982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        public void describeTo(Description description) {
12082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            description.appendText("should have ").appendValue(mCount).appendText(" EmojiSpans");
12182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
12282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
12382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
12482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        protected void describeMismatchSafely(final CharSequence charSequence,
12582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                Description mismatchDescription) {
12682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mismatchDescription.appendText(" has ");
12782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (mSpans == null) {
12882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                mismatchDescription.appendValue("no");
12982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            } else {
13082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                mismatchDescription.appendValue(mSpans.length);
13182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
13282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
13382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mismatchDescription.appendText(" EmojiSpans");
13482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
13582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
13682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
13782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        protected boolean matchesSafely(final CharSequence charSequence) {
13882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (charSequence == null) return false;
13982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (!(charSequence instanceof Spanned)) return false;
14082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
14182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            return mSpans.length == mCount;
14282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
14382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
14482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
14582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    private static class EmojiResourceMatcher extends TypeSafeMatcher<CharSequence> {
14682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private static final int ERR_NONE = 0;
14782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private static final int ERR_SPANNABLE_NULL = 1;
14882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private static final int ERR_NO_SPANS = 2;
14982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private static final int ERR_WRONG_INDEX = 3;
15082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private final int mResId;
15182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private final int mStart;
15282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private final int mEnd;
15382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private int mError = ERR_NONE;
15482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private int mActualStart = -1;
15582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        private int mActualEnd = -1;
15682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
15782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        EmojiResourceMatcher(int resId, int start, int end) {
15882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mResId = resId;
15982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mStart = start;
16082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mEnd = end;
16182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
16282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
16382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
16482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        public void describeTo(final Description description) {
16582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (mResId == -1) {
16682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                description.appendText("should have EmojiSpan at ")
16782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        .appendValue("[" + mStart + "," + mEnd + "]");
16882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            } else if (mStart == -1 && mEnd == -1) {
16982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                description.appendText("should have EmojiSpan with resource id ")
17082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        .appendValue(Integer.toHexString(mResId));
17182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            } else {
17282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                description.appendText("should have EmojiSpan with resource id ")
17382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        .appendValue(Integer.toHexString(mResId))
17482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        .appendText(" at ")
17582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        .appendValue("[" + mStart + "," + mEnd + "]");
17682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
17782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
17882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
17982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
18082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        protected void describeMismatchSafely(final CharSequence charSequence,
18182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                Description mismatchDescription) {
18282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            int offset = 0;
18382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mismatchDescription.appendText("[");
18482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            while (offset < charSequence.length()) {
18582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                int codepoint = Character.codePointAt(charSequence, offset);
18682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                mismatchDescription.appendText(Integer.toHexString(codepoint));
18782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                offset += Character.charCount(codepoint);
18882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                if (offset < charSequence.length()) {
18982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    mismatchDescription.appendText(",");
19082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                }
19182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
19282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            mismatchDescription.appendText("]");
19382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
19482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            switch (mError) {
19582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                case ERR_NO_SPANS:
19682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    mismatchDescription.appendText(" had no spans");
19782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    break;
19882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                case ERR_SPANNABLE_NULL:
19982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    mismatchDescription.appendText(" was null");
20082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    break;
20182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                case ERR_WRONG_INDEX:
20282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    mismatchDescription.appendText(" had Emoji at ")
20382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                            .appendValue("[" + mActualStart + "," + mActualEnd + "]");
20482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    break;
20582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                default:
20682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    mismatchDescription.appendText(" does not have an EmojiSpan with given "
20782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                            + "resource id ");
20882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
20982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
21082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
21182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        @Override
21282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        protected boolean matchesSafely(final CharSequence charSequence) {
21382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (charSequence == null) {
21482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                mError = ERR_SPANNABLE_NULL;
21582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                return false;
21682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
21782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
21882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (!(charSequence instanceof Spanned)) {
21982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                mError = ERR_NO_SPANS;
22082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                return false;
22182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
22282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
22382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            Spanned spanned = (Spanned) charSequence;
22482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class);
22582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
22682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (spans.length == 0) {
22782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                mError = ERR_NO_SPANS;
22882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                return false;
22982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
23082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
23182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            if (mStart == -1 && mEnd == -1) {
23282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                for (int index = 0; index < spans.length; index++) {
23382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    if (mResId == spans[index].getId()) {
23482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        return true;
23582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    }
23682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                }
23782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                return false;
23882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            } else {
23982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                for (int index = 0; index < spans.length; index++) {
24082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    if (mResId == -1 || mResId == spans[index].getId()) {
24182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        mActualStart = spanned.getSpanStart(spans[index]);
24282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        mActualEnd = spanned.getSpanEnd(spans[index]);
24382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        if (mActualStart == mStart && mActualEnd == mEnd) {
24482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                            return true;
24582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                        }
24682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    }
24782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                }
24882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
24982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                if (mActualStart != -1 && mActualEnd != -1) {
25082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                    mError = ERR_WRONG_INDEX;
25182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                }
25282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir
25382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir                return false;
25482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir            }
25582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir        }
25682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir    }
25782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir}
258