182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/* 282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Copyright (C) 2017 The Android Open Source Project 382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License"); 582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * you may not use this file except in compliance with the License. 682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * You may obtain a copy of the License at 782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * http://www.apache.org/licenses/LICENSE-2.0 982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 1082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Unless required by applicable law or agreed to in writing, software 1182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS, 1282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * See the License for the specific language governing permissions and 1482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * limitations under the License. 1582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 1682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirpackage android.support.text.emoji; 1782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 1882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 1982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 2082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.content.res.AssetManager; 2182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.graphics.Typeface; 2282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.annotation.AnyThread; 2382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.annotation.NonNull; 2477b5c5b734f9f665577d1e3d178615db43ae1d4fSiyamed Sinirimport android.support.annotation.RequiresApi; 2582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.annotation.RestrictTo; 2682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.annotation.VisibleForTesting; 2782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.text.emoji.flatbuffer.MetadataList; 2882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.support.v4.util.Preconditions; 2982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport android.util.SparseArray; 3082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 3182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.io.IOException; 3282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.io.InputStream; 3382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirimport java.nio.ByteBuffer; 3482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 3582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir/** 3682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Class to hold the emoji metadata required to process and draw emojis. 3782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 3882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir@AnyThread 3977b5c5b734f9f665577d1e3d178615db43ae1d4fSiyamed Sinir@RequiresApi(19) 4082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinirpublic final class MetadataRepo { 4182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 4282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * The default children size of the root node. 4382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 4482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private static final int DEFAULT_ROOT_SIZE = 1024; 4582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 4682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 4782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * MetadataList that contains the emoji metadata. 4882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 4982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final MetadataList mMetadataList; 5082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 5182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 5282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * char presentation of all EmojiMetadata's in a single array. 5382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 5482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final char[] mEmojiCharArray; 5582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 5682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 5782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Empty root node of the trie. 5882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 5982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final Node mRootNode; 6082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 6282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Typeface to be used to render emojis. 6382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 6482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private final Typeface mTypeface; 6582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 6682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 6782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Constructor used for tests. 6882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 6982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 7082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 7182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 7282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir MetadataRepo() { 7382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mTypeface = null; 7482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mMetadataList = null; 7582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mRootNode = new Node(DEFAULT_ROOT_SIZE); 7682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mEmojiCharArray = new char[0]; 7782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 7882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 7982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 8082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Private constructor that is called by one of {@code create} methods. 8182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 8282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param typeface Typeface to be used to render emojis 8382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param metadataList MetadataList that contains the emoji metadata 8482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 8582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private MetadataRepo(@NonNull final Typeface typeface, 8682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @NonNull final MetadataList metadataList) { 8782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mTypeface = typeface; 8882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mMetadataList = metadataList; 8982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mRootNode = new Node(DEFAULT_ROOT_SIZE); 9082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mEmojiCharArray = new char[mMetadataList.listLength() * 2]; 9182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir constructIndex(mMetadataList); 9282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 9382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 9482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 9582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Construct MetadataRepo from an input stream. The library does not close the given 9682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * InputStream, therefore it is caller's responsibility to properly close the stream. 9782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 9882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param typeface Typeface to be used to render emojis 9982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param inputStream InputStream to read emoji metadata from 10082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 10182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static MetadataRepo create(@NonNull final Typeface typeface, 10282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @NonNull final InputStream inputStream) throws IOException { 10382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new MetadataRepo(typeface, MetadataListReader.read(inputStream)); 10482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 10582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 10682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 10782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Construct MetadataRepo from a byte buffer. The position of the ByteBuffer will change, it is 10882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * caller's responsibility to reposition the buffer if required. 10982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 11082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param typeface Typeface to be used to render emojis 11182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param byteBuffer ByteBuffer to read emoji metadata from 11282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 11382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static MetadataRepo create(@NonNull final Typeface typeface, 11482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @NonNull final ByteBuffer byteBuffer) throws IOException { 11582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new MetadataRepo(typeface, MetadataListReader.read(byteBuffer)); 11682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 11782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 11882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 11982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Construct MetadataRepo from an asset. 12082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 12182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param assetManager AssetManager instance 12282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @param assetPath asset manager path of the file that the Typeface and metadata will be 12382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * created from 12482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 12582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public static MetadataRepo create(@NonNull final AssetManager assetManager, 12682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final String assetPath) throws IOException { 12782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final Typeface typeface = Typeface.createFromAsset(assetManager, assetPath); 12882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return new MetadataRepo(typeface, MetadataListReader.read(assetManager, assetPath)); 12982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 13082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 13182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 13282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Read emoji metadata list and construct the trie. 13382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 13482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private void constructIndex(final MetadataList metadataList) { 13582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir int length = metadataList.listLength(); 13682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir for (int i = 0; i < length; i++) { 13782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final EmojiMetadata metadata = new EmojiMetadata(this, i); 13882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Character.toChars(metadata.getId(), mEmojiCharArray, i * 2); 13982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir put(metadata); 14082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 14182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 14282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 14382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 14482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 14582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 14682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 14782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Typeface getTypeface() { 14882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mTypeface; 14982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 15082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 15182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 15282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 15382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 15482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 15582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir int getMetadataVersion() { 15682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mMetadataList.version(); 15782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 15882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 15982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 16082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 16182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 16282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 16382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Node getRootNode() { 16482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mRootNode; 16582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 16682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 16782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 16882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 16982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 17082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 17182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public char[] getEmojiCharArray() { 17282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mEmojiCharArray; 17382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 17482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 17582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 17682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 17782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 17882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 17982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir public MetadataList getMetadataList() { 18082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mMetadataList; 18182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 18282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 18382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 18482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Add an EmojiMetadata to the index. 18582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 18682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 18782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 18882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 18982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @VisibleForTesting 19082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir void put(@NonNull final EmojiMetadata data) { 19182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Preconditions.checkNotNull(data, "emoji metadata cannot be null"); 19282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Preconditions.checkArgument(data.getCodepointsLength() > 0, 19382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir "invalid metadata codepoint length"); 19482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 19582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mRootNode.put(data, 0, data.getCodepointsLength() - 1); 19682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 19782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 19882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir /** 19982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * Trie node that holds mapping from emoji codepoint(s) to EmojiMetadata. A single codepoint 20082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * emoji is represented by a child of the root node. 20182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * 20282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir * @hide 20382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir */ 20482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir @RestrictTo(LIBRARY_GROUP) 20582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir static class Node { 20682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private SparseArray<Node> mChildren; 20782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private EmojiMetadata mData; 20882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 20982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private Node() { 21082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 21182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 21282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private Node(final int defaultChildrenSize) { 21382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mChildren = new SparseArray<>(defaultChildrenSize); 21482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 21582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 21682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Node get(final int key) { 21782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mChildren == null ? null : mChildren.get(key); 21882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 21982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 22082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir final EmojiMetadata getData() { 22182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir return mData; 22282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 22382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 22482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir private void put(@NonNull final EmojiMetadata data, final int start, final int end) { 22582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir Node node = get(data.getCodepointAt(start)); 22682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (node == null) { 22782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (mChildren == null) { 22882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mChildren = new SparseArray<>(1); 22982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir node = new Node(); 23182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir mChildren.put(data.getCodepointAt(start), node); 23282d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23382d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir 23482d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir if (end > start) { 23582d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir node.put(data, start + 1, end); 23682d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } else { 23782d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir node.mData = data; 23882d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 23982d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 24082d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir } 24182d2cc1cf0c2bfdd5121e6d6913dfe9fcaacf439Siyamed Sinir} 242