package im.delight.faceless; /* * Copyright (c) delight.im <[email protected]> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** Source: <https://github.com/delight-im/Emoji> */ import android.text.Spanned; import android.text.SpannableStringBuilder; import android.content.Context; import android.graphics.Paint; import android.graphics.Typeface; import android.text.TextPaint; import android.text.style.MetricAffectingSpan; /** * Emoji support for Android down to API level 8 (Android 2.2) * <p> * Usage: CharSequence myCharSequence = AndroidEmoji.ensure(myString); */ public class AndroidEmoji { /** * Span to set on TextView instances in order to have a custom font for single parts of a text * * <pre> * SpannableStringBuilder ssb = new SpannableStringBuilder(myStringToShow); * ssb.setSpan(new CustomTypefaceSpan(myTypeface), myFromPosition, myToPosition, Spanned.SPAN_EXCLUSIVE_INCLUSIVE); * myTextView.setText(ssb); * </pre> * * @author Benjamin Dobell */ private static class CustomTypefaceSpan extends MetricAffectingSpan { private final Typeface mTypeface; public CustomTypefaceSpan(final Typeface typeface) { mTypeface = typeface; } @Override public void updateDrawState(final TextPaint drawState) { apply(drawState); } @Override public void updateMeasureState(final TextPaint paint) { apply(paint); } private void apply(final Paint paint) { final Typeface oldTypeface = paint.getTypeface(); final int oldStyle = oldTypeface != null ? oldTypeface.getStyle() : 0; final int fakeStyle = oldStyle & ~mTypeface.getStyle(); if ((fakeStyle & Typeface.BOLD) != 0) { paint.setFakeBoldText(true); } if ((fakeStyle & Typeface.ITALIC) != 0) { paint.setTextSkewX(-0.25f); } paint.setTypeface(mTypeface); } } /** * Manages the reference to the emoji font * <p> * Usage: FontProvider.getInstance(context).getFontEmoji() */ private static class FontProvider { private static final String PATH_EMOJI = "fonts/AndroidEmoji.ttf"; private static FontProvider mInstance; private Typeface mFontEmoji; public static FontProvider getInstance(Context context) { if (mInstance == null) { mInstance = new FontProvider(context.getApplicationContext()); } return mInstance; } private FontProvider(Context context) { mFontEmoji = Typeface.createFromAsset(context.getAssets(), PATH_EMOJI); } public Typeface getFontEmoji() { return mFontEmoji; } } /** * Compares the given code point against 722 emoji code points from Unicode 6.3 * <p> * Reference: EmojiSources.txt by Unicode, Inc. (http://www.unicode.org/Public/UNIDATA/EmojiSources.txt) * * @param codePoint the code point to check * @return whether the code point represents an emoji or not */ private static boolean isEmoji(int codePoint) { return // Digits and number sign on keys (actually defined in concatenated form) // codePoint == 0x0023 0x20E3 || // codePoint == 0x0030 0x20E3 || // codePoint == 0x0031 0x20E3 || // codePoint == 0x0032 0x20E3 || // codePoint == 0x0033 0x20E3 || // codePoint == 0x0034 0x20E3 || // codePoint == 0x0035 0x20E3 || // codePoint == 0x0036 0x20E3 || // codePoint == 0x0037 0x20E3 || // codePoint == 0x0038 0x20E3 || // codePoint == 0x0039 0x20E3 || codePoint == 0x00A9 || codePoint == 0x00AE || codePoint == 0x2002 || codePoint == 0x2003 || codePoint == 0x2005 || codePoint == 0x203C || codePoint == 0x2049 || codePoint == 0x2122 || codePoint == 0x2139 || codePoint == 0x2194 || codePoint == 0x2195 || codePoint == 0x2196 || codePoint == 0x2197 || codePoint == 0x2198 || codePoint == 0x2199 || codePoint == 0x21A9 || codePoint == 0x21AA || codePoint == 0x231A || codePoint == 0x231B || codePoint == 0x23E9 || codePoint == 0x23EA || codePoint == 0x23EB || codePoint == 0x23EC || codePoint == 0x23F0 || codePoint == 0x23F3 || codePoint == 0x24C2 || codePoint == 0x25AA || codePoint == 0x25AB || codePoint == 0x25B6 || codePoint == 0x25C0 || codePoint == 0x25FB || codePoint == 0x25FC || codePoint == 0x25FD || codePoint == 0x25FE || codePoint == 0x2600 || codePoint == 0x2601 || codePoint == 0x260E || codePoint == 0x2611 || codePoint == 0x2614 || codePoint == 0x2615 || codePoint == 0x261D || codePoint == 0x263A || codePoint == 0x2648 || codePoint == 0x2649 || codePoint == 0x264A || codePoint == 0x264B || codePoint == 0x264C || codePoint == 0x264D || codePoint == 0x264E || codePoint == 0x264F || codePoint == 0x2650 || codePoint == 0x2651 || codePoint == 0x2652 || codePoint == 0x2653 || codePoint == 0x2660 || codePoint == 0x2663 || codePoint == 0x2665 || codePoint == 0x2666 || codePoint == 0x2668 || codePoint == 0x267B || codePoint == 0x267F || codePoint == 0x2693 || codePoint == 0x26A0 || codePoint == 0x26A1 || codePoint == 0x26AA || codePoint == 0x26AB || codePoint == 0x26BD || codePoint == 0x26BE || codePoint == 0x26C4 || codePoint == 0x26C5 || codePoint == 0x26CE || codePoint == 0x26D4 || codePoint == 0x26EA || codePoint == 0x26F2 || codePoint == 0x26F3 || codePoint == 0x26F5 || codePoint == 0x26FA || codePoint == 0x26FD || codePoint == 0x2702 || codePoint == 0x2705 || codePoint == 0x2708 || codePoint == 0x2709 || codePoint == 0x270A || codePoint == 0x270B || codePoint == 0x270C || codePoint == 0x270F || codePoint == 0x2712 || codePoint == 0x2714 || codePoint == 0x2716 || codePoint == 0x2728 || codePoint == 0x2733 || codePoint == 0x2734 || codePoint == 0x2744 || codePoint == 0x2747 || codePoint == 0x274C || codePoint == 0x274E || codePoint == 0x2753 || codePoint == 0x2754 || codePoint == 0x2755 || codePoint == 0x2757 || codePoint == 0x2764 || codePoint == 0x2795 || codePoint == 0x2796 || codePoint == 0x2797 || codePoint == 0x27A1 || codePoint == 0x27B0 || codePoint == 0x2934 || codePoint == 0x2935 || codePoint == 0x2B05 || codePoint == 0x2B06 || codePoint == 0x2B07 || codePoint == 0x2B1B || codePoint == 0x2B1C || codePoint == 0x2B50 || codePoint == 0x2B55 || codePoint == 0x3030 || codePoint == 0x303D || codePoint == 0x3297 || codePoint == 0x3299 || codePoint == 0x1F004 || codePoint == 0x1F0CF || codePoint == 0x1F170 || codePoint == 0x1F171 || codePoint == 0x1F17E || codePoint == 0x1F17F || codePoint == 0x1F18E || codePoint == 0x1F191 || codePoint == 0x1F192 || codePoint == 0x1F193 || codePoint == 0x1F194 || codePoint == 0x1F195 || codePoint == 0x1F196 || codePoint == 0x1F197 || codePoint == 0x1F198 || codePoint == 0x1F199 || codePoint == 0x1F19A || // Regional Indicator Symbols (actually defined in concatenated form) (codePoint == 0x1F1E8 || codePoint == 0x1F1F3) || (codePoint == 0x1F1E9 || codePoint == 0x1F1EA) || (codePoint == 0x1F1EA || codePoint == 0x1F1F8) || (codePoint == 0x1F1EB || codePoint == 0x1F1F7) || (codePoint == 0x1F1EC || codePoint == 0x1F1E7) || (codePoint == 0x1F1EE || codePoint == 0x1F1F9) || (codePoint == 0x1F1EF || codePoint == 0x1F1F5) || (codePoint == 0x1F1F0 || codePoint == 0x1F1F7) || (codePoint == 0x1F1F7 || codePoint == 0x1F1FA) || (codePoint == 0x1F1FA || codePoint == 0x1F1F8) || codePoint == 0x1F201 || codePoint == 0x1F202 || codePoint == 0x1F21A || codePoint == 0x1F22F || codePoint == 0x1F232 || codePoint == 0x1F233 || codePoint == 0x1F234 || codePoint == 0x1F235 || codePoint == 0x1F236 || codePoint == 0x1F237 || codePoint == 0x1F238 || codePoint == 0x1F239 || codePoint == 0x1F23A || codePoint == 0x1F250 || codePoint == 0x1F251 || codePoint == 0x1F300 || codePoint == 0x1F301 || codePoint == 0x1F302 || codePoint == 0x1F303 || codePoint == 0x1F304 || codePoint == 0x1F305 || codePoint == 0x1F306 || codePoint == 0x1F307 || codePoint == 0x1F308 || codePoint == 0x1F309 || codePoint == 0x1F30A || codePoint == 0x1F30B || codePoint == 0x1F30C || codePoint == 0x1F30F || codePoint == 0x1F311 || codePoint == 0x1F313 || codePoint == 0x1F314 || codePoint == 0x1F315 || codePoint == 0x1F319 || codePoint == 0x1F31B || codePoint == 0x1F31F || codePoint == 0x1F320 || codePoint == 0x1F330 || codePoint == 0x1F331 || codePoint == 0x1F334 || codePoint == 0x1F335 || codePoint == 0x1F337 || codePoint == 0x1F338 || codePoint == 0x1F339 || codePoint == 0x1F33A || codePoint == 0x1F33B || codePoint == 0x1F33C || codePoint == 0x1F33D || codePoint == 0x1F33E || codePoint == 0x1F33F || codePoint == 0x1F340 || codePoint == 0x1F341 || codePoint == 0x1F342 || codePoint == 0x1F343 || codePoint == 0x1F344 || codePoint == 0x1F345 || codePoint == 0x1F346 || codePoint == 0x1F347 || codePoint == 0x1F348 || codePoint == 0x1F349 || codePoint == 0x1F34A || codePoint == 0x1F34C || codePoint == 0x1F34D || codePoint == 0x1F34E || codePoint == 0x1F34F || codePoint == 0x1F351 || codePoint == 0x1F352 || codePoint == 0x1F353 || codePoint == 0x1F354 || codePoint == 0x1F355 || codePoint == 0x1F356 || codePoint == 0x1F357 || codePoint == 0x1F358 || codePoint == 0x1F359 || codePoint == 0x1F35A || codePoint == 0x1F35B || codePoint == 0x1F35C || codePoint == 0x1F35D || codePoint == 0x1F35E || codePoint == 0x1F35F || codePoint == 0x1F360 || codePoint == 0x1F361 || codePoint == 0x1F362 || codePoint == 0x1F363 || codePoint == 0x1F364 || codePoint == 0x1F365 || codePoint == 0x1F366 || codePoint == 0x1F367 || codePoint == 0x1F368 || codePoint == 0x1F369 || codePoint == 0x1F36A || codePoint == 0x1F36B || codePoint == 0x1F36C || codePoint == 0x1F36D || codePoint == 0x1F36E || codePoint == 0x1F36F || codePoint == 0x1F370 || codePoint == 0x1F371 || codePoint == 0x1F372 || codePoint == 0x1F373 || codePoint == 0x1F374 || codePoint == 0x1F375 || codePoint == 0x1F376 || codePoint == 0x1F377 || codePoint == 0x1F378 || codePoint == 0x1F379 || codePoint == 0x1F37A || codePoint == 0x1F37B || codePoint == 0x1F380 || codePoint == 0x1F381 || codePoint == 0x1F382 || codePoint == 0x1F383 || codePoint == 0x1F384 || codePoint == 0x1F385 || codePoint == 0x1F386 || codePoint == 0x1F387 || codePoint == 0x1F388 || codePoint == 0x1F389 || codePoint == 0x1F38A || codePoint == 0x1F38B || codePoint == 0x1F38C || codePoint == 0x1F38D || codePoint == 0x1F38E || codePoint == 0x1F38F || codePoint == 0x1F390 || codePoint == 0x1F391 || codePoint == 0x1F392 || codePoint == 0x1F393 || codePoint == 0x1F3A0 || codePoint == 0x1F3A1 || codePoint == 0x1F3A2 || codePoint == 0x1F3A3 || codePoint == 0x1F3A4 || codePoint == 0x1F3A5 || codePoint == 0x1F3A6 || codePoint == 0x1F3A7 || codePoint == 0x1F3A8 || codePoint == 0x1F3A9 || codePoint == 0x1F3AA || codePoint == 0x1F3AB || codePoint == 0x1F3AC || codePoint == 0x1F3AD || codePoint == 0x1F3AE || codePoint == 0x1F3AF || codePoint == 0x1F3B0 || codePoint == 0x1F3B1 || codePoint == 0x1F3B2 || codePoint == 0x1F3B3 || codePoint == 0x1F3B4 || codePoint == 0x1F3B5 || codePoint == 0x1F3B6 || codePoint == 0x1F3B7 || codePoint == 0x1F3B8 || codePoint == 0x1F3B9 || codePoint == 0x1F3BA || codePoint == 0x1F3BB || codePoint == 0x1F3BC || codePoint == 0x1F3BD || codePoint == 0x1F3BE || codePoint == 0x1F3BF || codePoint == 0x1F3C0 || codePoint == 0x1F3C1 || codePoint == 0x1F3C2 || codePoint == 0x1F3C3 || codePoint == 0x1F3C4 || codePoint == 0x1F3C6 || codePoint == 0x1F3C8 || codePoint == 0x1F3CA || codePoint == 0x1F3E0 || codePoint == 0x1F3E1 || codePoint == 0x1F3E2 || codePoint == 0x1F3E3 || codePoint == 0x1F3E5 || codePoint == 0x1F3E6 || codePoint == 0x1F3E7 || codePoint == 0x1F3E8 || codePoint == 0x1F3E9 || codePoint == 0x1F3EA || codePoint == 0x1F3EB || codePoint == 0x1F3EC || codePoint == 0x1F3ED || codePoint == 0x1F3EE || codePoint == 0x1F3EF || codePoint == 0x1F3F0 || codePoint == 0x1F40C || codePoint == 0x1F40D || codePoint == 0x1F40E || codePoint == 0x1F411 || codePoint == 0x1F412 || codePoint == 0x1F414 || codePoint == 0x1F417 || codePoint == 0x1F418 || codePoint == 0x1F419 || codePoint == 0x1F41A || codePoint == 0x1F41B || codePoint == 0x1F41C || codePoint == 0x1F41D || codePoint == 0x1F41E || codePoint == 0x1F41F || codePoint == 0x1F420 || codePoint == 0x1F421 || codePoint == 0x1F422 || codePoint == 0x1F423 || codePoint == 0x1F424 || codePoint == 0x1F425 || codePoint == 0x1F426 || codePoint == 0x1F427 || codePoint == 0x1F428 || codePoint == 0x1F429 || codePoint == 0x1F42B || codePoint == 0x1F42C || codePoint == 0x1F42D || codePoint == 0x1F42E || codePoint == 0x1F42F || codePoint == 0x1F430 || codePoint == 0x1F431 || codePoint == 0x1F432 || codePoint == 0x1F433 || codePoint == 0x1F434 || codePoint == 0x1F435 || codePoint == 0x1F436 || codePoint == 0x1F437 || codePoint == 0x1F438 || codePoint == 0x1F439 || codePoint == 0x1F43A || codePoint == 0x1F43B || codePoint == 0x1F43C || codePoint == 0x1F43D || codePoint == 0x1F43E || codePoint == 0x1F440 || codePoint == 0x1F442 || codePoint == 0x1F443 || codePoint == 0x1F444 || codePoint == 0x1F445 || codePoint == 0x1F446 || codePoint == 0x1F447 || codePoint == 0x1F448 || codePoint == 0x1F449 || codePoint == 0x1F44A || codePoint == 0x1F44B || codePoint == 0x1F44C || codePoint == 0x1F44D || codePoint == 0x1F44E || codePoint == 0x1F44F || codePoint == 0x1F450 || codePoint == 0x1F451 || codePoint == 0x1F452 || codePoint == 0x1F453 || codePoint == 0x1F454 || codePoint == 0x1F455 || codePoint == 0x1F456 || codePoint == 0x1F457 || codePoint == 0x1F458 || codePoint == 0x1F459 || codePoint == 0x1F45A || codePoint == 0x1F45B || codePoint == 0x1F45C || codePoint == 0x1F45D || codePoint == 0x1F45E || codePoint == 0x1F45F || codePoint == 0x1F460 || codePoint == 0x1F461 || codePoint == 0x1F462 || codePoint == 0x1F463 || codePoint == 0x1F464 || codePoint == 0x1F466 || codePoint == 0x1F467 || codePoint == 0x1F468 || codePoint == 0x1F469 || codePoint == 0x1F46A || codePoint == 0x1F46B || codePoint == 0x1F46E || codePoint == 0x1F46F || codePoint == 0x1F470 || codePoint == 0x1F471 || codePoint == 0x1F472 || codePoint == 0x1F473 || codePoint == 0x1F474 || codePoint == 0x1F475 || codePoint == 0x1F476 || codePoint == 0x1F477 || codePoint == 0x1F478 || codePoint == 0x1F479 || codePoint == 0x1F47A || codePoint == 0x1F47B || codePoint == 0x1F47C || codePoint == 0x1F47D || codePoint == 0x1F47E || codePoint == 0x1F47F || codePoint == 0x1F480 || codePoint == 0x1F481 || codePoint == 0x1F482 || codePoint == 0x1F483 || codePoint == 0x1F484 || codePoint == 0x1F485 || codePoint == 0x1F486 || codePoint == 0x1F487 || codePoint == 0x1F488 || codePoint == 0x1F489 || codePoint == 0x1F48A || codePoint == 0x1F48B || codePoint == 0x1F48C || codePoint == 0x1F48D || codePoint == 0x1F48E || codePoint == 0x1F48F || codePoint == 0x1F490 || codePoint == 0x1F491 || codePoint == 0x1F492 || codePoint == 0x1F493 || codePoint == 0x1F494 || codePoint == 0x1F495 || codePoint == 0x1F496 || codePoint == 0x1F497 || codePoint == 0x1F498 || codePoint == 0x1F499 || codePoint == 0x1F49A || codePoint == 0x1F49B || codePoint == 0x1F49C || codePoint == 0x1F49D || codePoint == 0x1F49E || codePoint == 0x1F49F || codePoint == 0x1F4A0 || codePoint == 0x1F4A1 || codePoint == 0x1F4A2 || codePoint == 0x1F4A3 || codePoint == 0x1F4A4 || codePoint == 0x1F4A5 || codePoint == 0x1F4A6 || codePoint == 0x1F4A7 || codePoint == 0x1F4A8 || codePoint == 0x1F4A9 || codePoint == 0x1F4AA || codePoint == 0x1F4AB || codePoint == 0x1F4AC || codePoint == 0x1F4AE || codePoint == 0x1F4AF || codePoint == 0x1F4B0 || codePoint == 0x1F4B1 || codePoint == 0x1F4B2 || codePoint == 0x1F4B3 || codePoint == 0x1F4B4 || codePoint == 0x1F4B5 || codePoint == 0x1F4B8 || codePoint == 0x1F4B9 || codePoint == 0x1F4BA || codePoint == 0x1F4BB || codePoint == 0x1F4BC || codePoint == 0x1F4BD || codePoint == 0x1F4BE || codePoint == 0x1F4BF || codePoint == 0x1F4C0 || codePoint == 0x1F4C1 || codePoint == 0x1F4C2 || codePoint == 0x1F4C3 || codePoint == 0x1F4C4 || codePoint == 0x1F4C5 || codePoint == 0x1F4C6 || codePoint == 0x1F4C7 || codePoint == 0x1F4C8 || codePoint == 0x1F4C9 || codePoint == 0x1F4CA || codePoint == 0x1F4CB || codePoint == 0x1F4CC || codePoint == 0x1F4CD || codePoint == 0x1F4CE || codePoint == 0x1F4CF || codePoint == 0x1F4D0 || codePoint == 0x1F4D1 || codePoint == 0x1F4D2 || codePoint == 0x1F4D3 || codePoint == 0x1F4D4 || codePoint == 0x1F4D5 || codePoint == 0x1F4D6 || codePoint == 0x1F4D7 || codePoint == 0x1F4D8 || codePoint == 0x1F4D9 || codePoint == 0x1F4DA || codePoint == 0x1F4DB || codePoint == 0x1F4DC || codePoint == 0x1F4DD || codePoint == 0x1F4DE || codePoint == 0x1F4DF || codePoint == 0x1F4E0 || codePoint == 0x1F4E1 || codePoint == 0x1F4E2 || codePoint == 0x1F4E3 || codePoint == 0x1F4E4 || codePoint == 0x1F4E5 || codePoint == 0x1F4E6 || codePoint == 0x1F4E7 || codePoint == 0x1F4E8 || codePoint == 0x1F4E9 || codePoint == 0x1F4EA || codePoint == 0x1F4EB || codePoint == 0x1F4EE || codePoint == 0x1F4F0 || codePoint == 0x1F4F1 || codePoint == 0x1F4F2 || codePoint == 0x1F4F3 || codePoint == 0x1F4F4 || codePoint == 0x1F4F6 || codePoint == 0x1F4F7 || codePoint == 0x1F4F9 || codePoint == 0x1F4FA || codePoint == 0x1F4FB || codePoint == 0x1F4FC || codePoint == 0x1F503 || codePoint == 0x1F50A || codePoint == 0x1F50B || codePoint == 0x1F50C || codePoint == 0x1F50D || codePoint == 0x1F50E || codePoint == 0x1F50F || codePoint == 0x1F510 || codePoint == 0x1F511 || codePoint == 0x1F512 || codePoint == 0x1F513 || codePoint == 0x1F514 || codePoint == 0x1F516 || codePoint == 0x1F517 || codePoint == 0x1F518 || codePoint == 0x1F519 || codePoint == 0x1F51A || codePoint == 0x1F51B || codePoint == 0x1F51C || codePoint == 0x1F51D || codePoint == 0x1F51E || codePoint == 0x1F51F || codePoint == 0x1F520 || codePoint == 0x1F521 || codePoint == 0x1F522 || codePoint == 0x1F523 || codePoint == 0x1F524 || codePoint == 0x1F525 || codePoint == 0x1F526 || codePoint == 0x1F527 || codePoint == 0x1F528 || codePoint == 0x1F529 || codePoint == 0x1F52A || codePoint == 0x1F52B || codePoint == 0x1F52E || codePoint == 0x1F52F || codePoint == 0x1F530 || codePoint == 0x1F531 || codePoint == 0x1F532 || codePoint == 0x1F533 || codePoint == 0x1F534 || codePoint == 0x1F535 || codePoint == 0x1F536 || codePoint == 0x1F537 || codePoint == 0x1F538 || codePoint == 0x1F539 || codePoint == 0x1F53A || codePoint == 0x1F53B || codePoint == 0x1F53C || codePoint == 0x1F53D || codePoint == 0x1F550 || codePoint == 0x1F551 || codePoint == 0x1F552 || codePoint == 0x1F553 || codePoint == 0x1F554 || codePoint == 0x1F555 || codePoint == 0x1F556 || codePoint == 0x1F557 || codePoint == 0x1F558 || codePoint == 0x1F559 || codePoint == 0x1F55A || codePoint == 0x1F55B || codePoint == 0x1F5FB || codePoint == 0x1F5FC || codePoint == 0x1F5FD || codePoint == 0x1F5FE || codePoint == 0x1F5FF || codePoint == 0x1F601 || codePoint == 0x1F602 || codePoint == 0x1F603 || codePoint == 0x1F604 || codePoint == 0x1F605 || codePoint == 0x1F606 || codePoint == 0x1F609 || codePoint == 0x1F60A || codePoint == 0x1F60B || codePoint == 0x1F60C || codePoint == 0x1F60D || codePoint == 0x1F60F || codePoint == 0x1F612 || codePoint == 0x1F613 || codePoint == 0x1F614 || codePoint == 0x1F616 || codePoint == 0x1F618 || codePoint == 0x1F61A || codePoint == 0x1F61C || codePoint == 0x1F61D || codePoint == 0x1F61E || codePoint == 0x1F620 || codePoint == 0x1F621 || codePoint == 0x1F622 || codePoint == 0x1F623 || codePoint == 0x1F624 || codePoint == 0x1F625 || codePoint == 0x1F628 || codePoint == 0x1F629 || codePoint == 0x1F62A || codePoint == 0x1F62B || codePoint == 0x1F62D || codePoint == 0x1F630 || codePoint == 0x1F631 || codePoint == 0x1F632 || codePoint == 0x1F633 || codePoint == 0x1F635 || codePoint == 0x1F637 || codePoint == 0x1F638 || codePoint == 0x1F639 || codePoint == 0x1F63A || codePoint == 0x1F63B || codePoint == 0x1F63C || codePoint == 0x1F63D || codePoint == 0x1F63E || codePoint == 0x1F63F || codePoint == 0x1F640 || codePoint == 0x1F645 || codePoint == 0x1F646 || codePoint == 0x1F647 || codePoint == 0x1F648 || codePoint == 0x1F649 || codePoint == 0x1F64A || codePoint == 0x1F64B || codePoint == 0x1F64C || codePoint == 0x1F64D || codePoint == 0x1F64E || codePoint == 0x1F64F || codePoint == 0x1F680 || codePoint == 0x1F683 || codePoint == 0x1F684 || codePoint == 0x1F685 || codePoint == 0x1F687 || codePoint == 0x1F689 || codePoint == 0x1F68C || codePoint == 0x1F68F || codePoint == 0x1F691 || codePoint == 0x1F692 || codePoint == 0x1F693 || codePoint == 0x1F695 || codePoint == 0x1F697 || codePoint == 0x1F699 || codePoint == 0x1F69A || codePoint == 0x1F6A2 || codePoint == 0x1F6A4 || codePoint == 0x1F6A5 || codePoint == 0x1F6A7 || codePoint == 0x1F6A8 || codePoint == 0x1F6A9 || codePoint == 0x1F6AA || codePoint == 0x1F6AB || codePoint == 0x1F6AC || codePoint == 0x1F6AD || codePoint == 0x1F6B2 || codePoint == 0x1F6B6 || codePoint == 0x1F6B9 || codePoint == 0x1F6BA || codePoint == 0x1F6BB || codePoint == 0x1F6BC || codePoint == 0x1F6BD || codePoint == 0x1F6BE || codePoint == 0x1F6C0; } /** * Ensures that all emoji in the given string will be displayed correctly by modifying the font for single symbols * * @param input the string to guarantee displayable emoji for * @param context the context to get the FontProvider instance from * @return the string with adjusted fonts as a CharSequence */ public static CharSequence ensure(String input, final Context context) { // if Android version is above 4.1.1 if (android.os.Build.VERSION.SDK_INT >= 17) { // return the text unchanged as emoji support is built-in already return input; } // if the input is null if (input == null) { // just return the input unchanged as it cannot be processed return input; } // extract the single chars that will be operated on final char[] chars = input.toCharArray(); // create a SpannableStringBuilder instance where the font ranges will be set for emoji characters final SpannableStringBuilder ssb = new SpannableStringBuilder(input); int codePoint; boolean isSurrogatePair; // check every char in the input text for (int i = 0; i < chars.length; i++) { // if the char is a leading part of a surrogate pair (Unicode) if (Character.isHighSurrogate(chars[i])) { // just ignore it and wait for the trailing part continue; } // if the char is a trailing part of a surrogate pair (Unicode) else if (Character.isLowSurrogate(chars[i])) { // if the char and its predecessor are indeed a valid surrogate pair if (i > 0 && Character.isSurrogatePair(chars[i-1], chars[i])) { // get the Unicode code point for the surrogate pair codePoint = Character.toCodePoint(chars[i-1], chars[i]); // remember that we have a surrogate pair here (which counts as two characters) isSurrogatePair = true; } // if the char and its predecessor are not actually a valid surrogate pair else { // just ignore it continue; } } // if the char is not part of a surrogate pair, i.e. a simple char from the BMP else { // get the Unicode code point by simply casting the char to int codePoint = (int) chars[i]; // remember that we have a BMP symbol here (which counts as a single character) isSurrogatePair = false; } // if the detected code point is a known emoji if (isEmoji(codePoint)) { // change the font for this symbol (two characters if surrogate pair) to the emoji font ssb.setSpan(new CustomTypefaceSpan(FontProvider.getInstance(context).getFontEmoji()), isSurrogatePair ? i-1 : i, i+1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE); } } // return the SpannableStringBuilder with adjusted fonts (implements CharSequence) return ssb; } }