1ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka/*
2ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Copyright (C) 2016 The Android Open Source Project
3ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka *
4ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
5ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * you may not use this file except in compliance with the License.
6ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * You may obtain a copy of the License at
7ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka *
8ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
9ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka *
10ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * Unless required by applicable law or agreed to in writing, software
11ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
12ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * See the License for the specific language governing permissions and
14ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * limitations under the License.
15ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka */
16ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
17ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakapackage android.text;
18ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
191bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournaderimport android.icu.lang.UCharacter;
201bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournaderimport android.icu.lang.UProperty;
21ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
22ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka/**
23ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * An utility class for Emoji.
24ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka * @hide
25ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka */
26ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonakapublic class Emoji {
27ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public static int COMBINING_ENCLOSING_KEYCAP = 0x20E3;
28ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
29ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public static int ZERO_WIDTH_JOINER = 0x200D;
30ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
31ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public static int VARIATION_SELECTOR_16 = 0xFE0F;
32ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
33d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka    public static int CANCEL_TAG = 0xE007F;
34d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka
351bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader    /**
361bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader     * Returns true if the given code point is regional indicator symbol.
371bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader     */
381bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader    public static boolean isRegionalIndicatorSymbol(int codePoint) {
391bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        return 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF;
40ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
41ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
421bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader    /**
431bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader     * Returns true if the given code point is emoji modifier.
441bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader     */
451bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader    public static boolean isEmojiModifier(int codePoint) {
461bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        return UCharacter.hasBinaryProperty(codePoint, UProperty.EMOJI_MODIFIER);
47ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
48ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
49ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    // Returns true if the given code point is emoji modifier base.
50ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public static boolean isEmojiModifierBase(int codePoint) {
511bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // These two characters were removed from Emoji_Modifier_Base in Emoji 4.0, but we need to
521bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // keep them as emoji modifier bases since there are fonts and user-generated text out there
531bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // that treats these as potential emoji bases.
541bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        if (codePoint == 0x1F91D || codePoint == 0x1F93C) {
551bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader            return true;
561bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        }
571bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // Emoji Modifier Base characters new in Unicode emoji 5.0.
581bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // From http://www.unicode.org/Public/emoji/5.0/emoji-data.txt
591bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // TODO: Remove once emoji-data.text 5.0 is in ICU or update to 6.0.
601bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        if (codePoint == 0x1F91F
611bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || (0x1F931 <= codePoint && codePoint <= 0x1F932)
621bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || (0x1F9D1 <= codePoint && codePoint <= 0x1F9DD)) {
631bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader            return true;
641bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        }
651bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        return UCharacter.hasBinaryProperty(codePoint, UProperty.EMOJI_MODIFIER_BASE);
66ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
67ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
68ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader    /**
69ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader     * Returns true if the character is a new emoji still not supported in our version of ICU.
70ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader     */
71ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader    public static boolean isNewEmoji(int codePoint) {
721bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // Emoji characters new in Unicode emoji 5.0.
731bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // From http://www.unicode.org/Public/emoji/5.0/emoji-data.txt
741bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader        // TODO: Remove once emoji-data.text 5.0 is in ICU or update to 6.0.
75ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader        if (codePoint < 0x1F6F7 || codePoint > 0x1F9E6) {
76ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader            // Optimization for characters outside the new emoji range.
77ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader            return false;
78ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader        }
79ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader        return (0x1F6F7 <= codePoint && codePoint <= 0x1F6F8)
801bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || codePoint == 0x1F91F
811bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || (0x1F928 <= codePoint && codePoint <= 0x1F92F)
821bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || (0x1F931 <= codePoint && codePoint <= 0x1F932)
831bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || codePoint == 0x1F94C
841bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || (0x1F95F <= codePoint && codePoint <= 0x1F96B)
851bf3ee56f02cf0f5746f3cf5423da3b48bce32cfRoozbeh Pournader                || (0x1F992 <= codePoint && codePoint <= 0x1F997)
86ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader                || (0x1F9D0 <= codePoint && codePoint <= 0x1F9E6);
87ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader    }
88ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader
89ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader    /**
90ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader     * Returns true if the character has Emoji property.
91ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader     */
92ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader    public static boolean isEmoji(int codePoint) {
93ce93f31035169fd81096cfc84fce63881ca79315Roozbeh Pournader        return isNewEmoji(codePoint) || UCharacter.hasBinaryProperty(codePoint, UProperty.EMOJI);
94ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
95ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka
96ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    // Returns true if the character can be a base character of COMBINING ENCLOSING KEYCAP.
97ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    public static boolean isKeycapBase(int codePoint) {
98ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka        return ('0' <= codePoint && codePoint <= '9') || codePoint == '#' || codePoint == '*';
99ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka    }
100d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka
101d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka    /**
102d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka     * Returns true if the character can be a part of tag_spec in emoji tag sequence.
103d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka     *
104d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka     * Note that 0xE007F (CANCEL TAG) is not included.
105d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka     */
106d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka    public static boolean isTagSpecChar(int codePoint) {
107d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka        return 0xE0020 <= codePoint && codePoint <= 0xE007E;
108d5eff80a7721123f2170ff9a983db9f06535d5b4Seigo Nonaka    }
109ff3bfd5a79a95dcfccd1b8ad6c08c715ce6fa0e3Seigo Nonaka}
110