1ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka/* 27674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen * Copyright (C) 2015 The Android Open Source Project 3ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * 4ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * you may not use this file except in compliance with the License. 6ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * You may obtain a copy of the License at 7ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * 8ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * 10ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 11ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * See the License for the specific language governing permissions and 14ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka * limitations under the License. 15ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka */ 16ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 179f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokapackage com.android.inputmethod.keyboard.emoji; 18ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 19ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport android.content.SharedPreferences; 20ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport android.content.res.Resources; 2127ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaokaimport android.content.res.TypedArray; 227674a653678b542d795b0bd05c241654ffe1015aChieu Nguyenimport android.graphics.Paint; 23ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport android.graphics.Rect; 24ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport android.os.Build; 25ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport android.util.Log; 26ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport android.util.Pair; 27ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 2878cff10f8d317641dd3531cce04e74502be8ad44Tadashi G. Takaokaimport com.android.inputmethod.compat.BuildCompatUtils; 29ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.Key; 30ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 31ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 32ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardLayoutSet; 33ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport com.android.inputmethod.latin.R; 34ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport com.android.inputmethod.latin.settings.Settings; 35ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 36ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport java.util.ArrayList; 37ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport java.util.Collections; 38ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport java.util.Comparator; 39ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport java.util.HashMap; 40ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport java.util.List; 41ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaokaimport java.util.concurrent.ConcurrentHashMap; 42ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 439f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokafinal class EmojiCategory { 44ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private final String TAG = EmojiCategory.class.getSimpleName(); 45ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 46ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_UNSPECIFIED = -1; 47ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public static final int ID_RECENTS = 0; 48ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_PEOPLE = 1; 49ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_OBJECTS = 2; 50ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_NATURE = 3; 51ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_PLACES = 4; 52ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_SYMBOLS = 5; 53ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int ID_EMOTICONS = 6; 547674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_FLAGS = 7; 557674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_SMILEY_PEOPLE = 8; 567674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_ANIMALS_NATURE = 9; 577674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_FOOD_DRINK = 10; 587674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_TRAVEL_PLACES = 11; 597674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_ACTIVITY = 12; 607674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_OBJECTS = 13; 617674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_SYMBOLS = 14; 627674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_FLAGS = 15; 637674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static final int ID_EIGHT_SMILEY_PEOPLE_BORING = 16; 64ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 65ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public final class CategoryProperties { 66ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public final int mCategoryId; 67ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public final int mPageCount; 68ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public CategoryProperties(final int categoryId, final int pageCount) { 69ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mCategoryId = categoryId; 70ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mPageCount = pageCount; 71ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 72ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 73ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 74ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final String[] sCategoryName = { 75ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka "recents", 76ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka "people", 77ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka "objects", 78ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka "nature", 79ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka "places", 80ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka "symbols", 817674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "emoticons", 827674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "flags", 837674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "smiley & people", 847674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "animals & nature", 857674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "food & drink", 867674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "travel & places", 877674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "activity", 887674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "objects2", 897674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "symbols2", 907674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "flags2", 917674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen "smiley & people2" }; 92ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 9327ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka private static final int[] sCategoryTabIconAttr = { 9427ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView_iconEmojiRecentsTab, 9527ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView_iconEmojiCategory1Tab, 9627ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView_iconEmojiCategory2Tab, 9727ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView_iconEmojiCategory3Tab, 9827ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView_iconEmojiCategory4Tab, 9927ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView_iconEmojiCategory5Tab, 1007674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory6Tab, 1017674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory7Tab, 1027674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory8Tab, 1037674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory9Tab, 1047674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory10Tab, 1057674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory11Tab, 1067674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory12Tab, 1077674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory13Tab, 1087674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory14Tab, 1097674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory15Tab, 1107674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.styleable.EmojiPalettesView_iconEmojiCategory16Tab }; 111ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 112ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int[] sAccessibilityDescriptionResourceIdsForCategories = { 113ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka R.string.spoken_descrption_emoji_category_recents, 114ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka R.string.spoken_descrption_emoji_category_people, 115ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka R.string.spoken_descrption_emoji_category_objects, 116ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka R.string.spoken_descrption_emoji_category_nature, 117ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka R.string.spoken_descrption_emoji_category_places, 118ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka R.string.spoken_descrption_emoji_category_symbols, 1197674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_emoticons, 1207674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_flags, 1217674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_eight_smiley_people, 1227674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_eight_animals_nature, 1237674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_eight_food_drink, 1247674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_eight_travel_places, 1257674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_eight_activity, 1267674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_objects, 1277674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_symbols, 1287674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_flags, 1297674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen R.string.spoken_descrption_emoji_category_eight_smiley_people }; 130ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 131ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final int[] sCategoryElementId = { 132ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka KeyboardId.ELEMENT_EMOJI_RECENTS, 133ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka KeyboardId.ELEMENT_EMOJI_CATEGORY1, 134ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka KeyboardId.ELEMENT_EMOJI_CATEGORY2, 135ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka KeyboardId.ELEMENT_EMOJI_CATEGORY3, 136ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka KeyboardId.ELEMENT_EMOJI_CATEGORY4, 137ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka KeyboardId.ELEMENT_EMOJI_CATEGORY5, 1387674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY6, 1397674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY7, 1407674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY8, 1417674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY9, 1427674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY10, 1437674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY11, 1447674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY12, 1457674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY13, 1467674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY14, 1477674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY15, 1487674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen KeyboardId.ELEMENT_EMOJI_CATEGORY16 }; 149ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 150ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private final SharedPreferences mPrefs; 151ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private final Resources mRes; 152ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private final int mMaxPageKeyCount; 153ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private final KeyboardLayoutSet mLayoutSet; 154a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka private final HashMap<String, Integer> mCategoryNameToIdMap = new HashMap<>(); 15527ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka private final int[] mCategoryTabIconId = new int[sCategoryName.length]; 156a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka private final ArrayList<CategoryProperties> mShownCategories = new ArrayList<>(); 157a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka private final ConcurrentHashMap<Long, DynamicGridKeyboard> mCategoryKeyboardMap = 158a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka new ConcurrentHashMap<>(); 159ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 160ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private int mCurrentCategoryId = EmojiCategory.ID_UNSPECIFIED; 161ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private int mCurrentCategoryPageId = 0; 162ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 163ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public EmojiCategory(final SharedPreferences prefs, final Resources res, 16427ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka final KeyboardLayoutSet layoutSet, final TypedArray emojiPaletteViewAttr) { 165ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mPrefs = prefs; 166ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mRes = res; 167ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mMaxPageKeyCount = res.getInteger(R.integer.config_emoji_keyboard_max_page_key_count); 168ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mLayoutSet = layoutSet; 169ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (int i = 0; i < sCategoryName.length; ++i) { 170ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mCategoryNameToIdMap.put(sCategoryName[i], i); 17127ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka mCategoryTabIconId[i] = emojiPaletteViewAttr.getResourceId( 17227ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka sCategoryTabIconAttr[i], 0); 173ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 17428e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov 17528e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov int defaultCategoryId = EmojiCategory.ID_SYMBOLS; 176ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka addShownCategoryId(EmojiCategory.ID_RECENTS); 17778cff10f8d317641dd3531cce04e74502be8ad44Tadashi G. Takaoka if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.KITKAT) { 1787674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen if (canShowUnicodeEightEmoji()) { 1797674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen defaultCategoryId = EmojiCategory.ID_EIGHT_SMILEY_PEOPLE; 1807674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_SMILEY_PEOPLE); 1817674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_ANIMALS_NATURE); 1827674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_FOOD_DRINK); 1837674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_TRAVEL_PLACES); 1847674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_ACTIVITY); 1857674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_OBJECTS); 1867674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_EIGHT_SYMBOLS); 1877674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_FLAGS); // Exclude combinations without glyphs. 1887674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } else { 1897674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen defaultCategoryId = EmojiCategory.ID_PEOPLE; 1907674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_PEOPLE); 1917674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_OBJECTS); 1927674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_NATURE); 1937674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_PLACES); 1947674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_SYMBOLS); 1957674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen if (canShowFlagEmoji()) { 1967674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen addShownCategoryId(EmojiCategory.ID_FLAGS); 1977674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } 1987674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } 199a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov } else { 200a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov addShownCategoryId(EmojiCategory.ID_SYMBOLS); 201ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 202ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka addShownCategoryId(EmojiCategory.ID_EMOTICONS); 20328e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov 20428e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov DynamicGridKeyboard recentsKbd = 2057674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen getKeyboard(EmojiCategory.ID_RECENTS, 0 /* categoryPageId */); 20628e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov recentsKbd.loadRecentKeys(mCategoryKeyboardMap.values()); 20728e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov 20828e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov mCurrentCategoryId = Settings.readLastShownEmojiCategoryId(mPrefs, defaultCategoryId); 209a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov Log.i(TAG, "Last Emoji category id is " + mCurrentCategoryId); 210a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov if (!isShownCategoryId(mCurrentCategoryId)) { 211a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov Log.i(TAG, "Last emoji category " + mCurrentCategoryId + 212a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov " is invalid, starting in " + defaultCategoryId); 213a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov mCurrentCategoryId = defaultCategoryId; 214a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov } else if (mCurrentCategoryId == EmojiCategory.ID_RECENTS && 21528e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov recentsKbd.getSortedKeys().isEmpty()) { 216a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov Log.i(TAG, "No recent emojis found, starting in category " + defaultCategoryId); 21728e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov mCurrentCategoryId = defaultCategoryId; 21828e65858d9f7e8f94e0b298275624703fd74af05Dmitry Torokhov } 219ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 220ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 221ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private void addShownCategoryId(final int categoryId) { 222ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // Load a keyboard of categoryId 2237674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen getKeyboard(categoryId, 0 /* categoryPageId */); 224ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final CategoryProperties properties = 225ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka new CategoryProperties(categoryId, getCategoryPageCount(categoryId)); 226ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mShownCategories.add(properties); 227ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 228ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 229a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov private boolean isShownCategoryId(final int categoryId) { 230a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov for (final CategoryProperties prop : mShownCategories) { 231a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov if (prop.mCategoryId == categoryId) { 232a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov return true; 233a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov } 234a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov } 235a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov return false; 236a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov } 237a2a057a991d825c85dd07d4d353ddbca4f9ad92dDmitry Torokhov 2385f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka public static String getCategoryName(final int categoryId, final int categoryPageId) { 239ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return sCategoryName[categoryId] + "-" + categoryPageId; 240ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 241ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 242ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getCategoryId(final String name) { 243ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final String[] strings = name.split("-"); 244ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return mCategoryNameToIdMap.get(strings[0]); 245ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 246ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 24727ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka public int getCategoryTabIcon(final int categoryId) { 24827ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka return mCategoryTabIconId[categoryId]; 249ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 250ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 251ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public String getAccessibilityDescription(final int categoryId) { 252ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return mRes.getString(sAccessibilityDescriptionResourceIdsForCategories[categoryId]); 253ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 254ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 255ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public ArrayList<CategoryProperties> getShownCategories() { 256ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return mShownCategories; 257ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 258ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 259ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getCurrentCategoryId() { 260ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return mCurrentCategoryId; 261ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 262ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 263ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getCurrentCategoryPageSize() { 264ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return getCategoryPageSize(mCurrentCategoryId); 265ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 266ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 267ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getCategoryPageSize(final int categoryId) { 268ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (final CategoryProperties prop : mShownCategories) { 269ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (prop.mCategoryId == categoryId) { 270ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return prop.mPageCount; 271ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 272ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 273ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Log.w(TAG, "Invalid category id: " + categoryId); 274ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // Should not reach here. 275ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return 0; 276ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 277ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 278ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public void setCurrentCategoryId(final int categoryId) { 279ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mCurrentCategoryId = categoryId; 280ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Settings.writeLastShownEmojiCategoryId(mPrefs, categoryId); 281ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 282ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 283ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public void setCurrentCategoryPageId(final int id) { 284ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mCurrentCategoryPageId = id; 285ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 286ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 287ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getCurrentCategoryPageId() { 288ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return mCurrentCategoryPageId; 289ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 290ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 291ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public void saveLastTypedCategoryPage() { 292ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Settings.writeLastTypedEmojiCategoryPageId( 293ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mPrefs, mCurrentCategoryId, mCurrentCategoryPageId); 294ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 295ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 296ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public boolean isInRecentTab() { 297ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return mCurrentCategoryId == EmojiCategory.ID_RECENTS; 298ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 299ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 300ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getTabIdFromCategoryId(final int categoryId) { 301ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (int i = 0; i < mShownCategories.size(); ++i) { 302ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (mShownCategories.get(i).mCategoryId == categoryId) { 303ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return i; 304ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 305ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 306ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Log.w(TAG, "categoryId not found: " + categoryId); 307ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return 0; 308ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 309ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 310ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // Returns the view pager's page position for the categoryId 311ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getPageIdFromCategoryId(final int categoryId) { 312ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final int lastSavedCategoryPageId = 313ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Settings.readLastTypedEmojiCategoryPageId(mPrefs, categoryId); 314ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka int sum = 0; 315ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (int i = 0; i < mShownCategories.size(); ++i) { 316ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final CategoryProperties props = mShownCategories.get(i); 317ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (props.mCategoryId == categoryId) { 318ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return sum + lastSavedCategoryPageId; 319ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 320ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka sum += props.mPageCount; 321ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 322ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Log.w(TAG, "categoryId not found: " + categoryId); 323ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return 0; 324ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 325ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 326ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getRecentTabId() { 327ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return getTabIdFromCategoryId(EmojiCategory.ID_RECENTS); 328ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 329ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 330ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private int getCategoryPageCount(final int categoryId) { 331ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); 332ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return (keyboard.getSortedKeys().size() - 1) / mMaxPageKeyCount + 1; 333ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 334ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 335ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // Returns a pair of the category id and the category page id from the view pager's page 336ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // position. The category page id is numbered in each category. And the view page position 337ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // is the position of the current shown page in the view pager which contains all pages of 338ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // all categories. 339ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(final int position) { 340ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka int sum = 0; 341ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (final CategoryProperties properties : mShownCategories) { 342ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final int temp = sum; 343ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka sum += properties.mPageCount; 344ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (sum > position) { 345a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka return new Pair<>(properties.mCategoryId, position - temp); 346ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 347ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 348ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return null; 349ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 350ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 351ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka // Returns a keyboard from the view pager's page position. 352ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public DynamicGridKeyboard getKeyboardFromPagePosition(final int position) { 353ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Pair<Integer, Integer> categoryAndId = 354ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka getCategoryIdAndPageIdFromPagePosition(position); 355ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (categoryAndId != null) { 356ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return getKeyboard(categoryAndId.first, categoryAndId.second); 357ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 358ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return null; 359ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 360ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 361ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static final Long getCategoryKeyboardMapKey(final int categoryId, final int id) { 36223a357d71d5d1a404975375fd376618a4fd2a596Ken Wakasa return (((long) categoryId) << Integer.SIZE) | id; 363ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 364ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 365ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { 366ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka synchronized (mCategoryKeyboardMap) { 3677674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen final Long categoryKeyboardMapKey = getCategoryKeyboardMapKey(categoryId, id); 3687674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen if (mCategoryKeyboardMap.containsKey(categoryKeyboardMapKey)) { 3697674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen return mCategoryKeyboardMap.get(categoryKeyboardMapKey); 370ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 371ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 372ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (categoryId == EmojiCategory.ID_RECENTS) { 373ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs, 374ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), 375ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mMaxPageKeyCount, categoryId); 3767674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen mCategoryKeyboardMap.put(categoryKeyboardMapKey, kbd); 377ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return kbd; 378ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 379ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 380ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]); 381ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Key[][] sortedKeys = sortKeysIntoPages( 382ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka keyboard.getSortedKeys(), mMaxPageKeyCount); 383ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (int pageId = 0; pageId < sortedKeys.length; ++pageId) { 384ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, 385ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), 386ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mMaxPageKeyCount, categoryId); 387ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (final Key emojiKey : sortedKeys[pageId]) { 388ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (emojiKey == null) { 389ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka break; 390ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 391ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka tempKeyboard.addKeyLast(emojiKey); 392ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 393ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka mCategoryKeyboardMap.put( 394ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka getCategoryKeyboardMapKey(categoryId, pageId), tempKeyboard); 395ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 3967674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen return mCategoryKeyboardMap.get(categoryKeyboardMapKey); 397ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 398ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 399ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 400ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int getTotalPageCountOfAllCategories() { 401ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka int sum = 0; 402ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (CategoryProperties properties : mShownCategories) { 403ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka sum += properties.mPageCount; 404ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 405ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return sum; 406ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 407ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 408ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static Comparator<Key> EMOJI_KEY_COMPARATOR = new Comparator<Key>() { 409ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka @Override 410ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka public int compare(final Key lhs, final Key rhs) { 411ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Rect lHitBox = lhs.getHitBox(); 412ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Rect rHitBox = rhs.getHitBox(); 413ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (lHitBox.top < rHitBox.top) { 414ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return -1; 415ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } else if (lHitBox.top > rHitBox.top) { 416ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return 1; 417ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 418ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (lHitBox.left < rHitBox.left) { 419ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return -1; 420ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } else if (lHitBox.left > rHitBox.left) { 421ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return 1; 422ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 423ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (lhs.getCode() == rhs.getCode()) { 424ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return 0; 425ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 426ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return lhs.getCode() < rhs.getCode() ? -1 : 1; 427ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 428ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka }; 429ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka 430ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka private static Key[][] sortKeysIntoPages(final List<Key> inKeys, final int maxPageCount) { 431a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka final ArrayList<Key> keys = new ArrayList<>(inKeys); 432ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka Collections.sort(keys, EMOJI_KEY_COMPARATOR); 433ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final int pageCount = (keys.size() - 1) / maxPageCount + 1; 434ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka final Key[][] retval = new Key[pageCount][maxPageCount]; 435ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (int i = 0; i < keys.size(); ++i) { 436ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka retval[i / maxPageCount][i % maxPageCount] = keys.get(i); 437ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 438ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka return retval; 439ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka } 4407674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen 4417674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static boolean canShowFlagEmoji() { 4427674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen Paint paint = new Paint(); 4437674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen String switzerland = "\uD83C\uDDE8\uD83C\uDDED"; // U+1F1E8 U+1F1ED Flag for Switzerland 4447674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen try { 4457674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen return paint.hasGlyph(switzerland); 4467674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } catch (NoSuchMethodError e) { 4477674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen // Compare display width of single-codepoint emoji to width of flag emoji to determine 4487674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen // whether flag is rendered as single glyph or two adjacent regional indicator symbols. 4497674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen float flagWidth = paint.measureText(switzerland); 4507674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen float standardWidth = paint.measureText("\uD83D\uDC27"); // U+1F427 Penguin 4517674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen return flagWidth < standardWidth * 1.25; 4527674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen // This assumes that a valid glyph for the flag emoji must be less than 1.25 times 4537674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen // the width of the penguin. 4547674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } 4557674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } 4567674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen 4577674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen private static boolean canShowUnicodeEightEmoji() { 4587674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen Paint paint = new Paint(); 4597674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen String cheese = "\uD83E\uDDC0"; // U+1F9C0 Cheese wedge 4607674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen try { 4617674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen return paint.hasGlyph(cheese); 4627674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } catch (NoSuchMethodError e) { 4637674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen float cheeseWidth = paint.measureText(cheese); 4647674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen float tofuWidth = paint.measureText("\uFFFE"); 4657674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen return cheeseWidth > tofuWidth; 4667674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen // This assumes that a valid glyph for the cheese wedge must be greater than the width 4677674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen // of the noncharacter. 4687674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } 4697674a653678b542d795b0bd05c241654ffe1015aChieu Nguyen } 470ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka} 471