17aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir/* 27aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Copyright (C) 2017 The Android Open Source Project 37aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 47aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License"); 57aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * you may not use this file except in compliance with the License. 67aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * You may obtain a copy of the License at 77aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 87aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * http://www.apache.org/licenses/LICENSE-2.0 97aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 107aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Unless required by applicable law or agreed to in writing, software 117aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS, 127aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * See the License for the specific language governing permissions and 147aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * limitations under the License. 157aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 167aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 177aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirpackage android.support.text.emoji.widget; 187aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 197aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP; 207aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 217aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.annotation.TargetApi; 227aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.content.Context; 237aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.inputmethodservice.ExtractEditText; 247aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.os.Build; 257aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.support.annotation.IntRange; 267aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.support.annotation.Nullable; 277aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.support.annotation.RestrictTo; 287aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.support.text.emoji.EmojiCompat; 29410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinirimport android.support.text.emoji.EmojiSpan; 307aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.util.AttributeSet; 317aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.view.inputmethod.EditorInfo; 327aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.view.inputmethod.InputConnection; 337aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 347aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir/** 357aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * ExtractEditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}. 367aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * When used on devices running API 18 or below, this widget acts as a {@link ExtractEditText} and 377aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * does not provide any emoji compatibility feature. 387aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 397aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @hide 407aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 417aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir@RestrictTo(LIBRARY_GROUP) 427aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirpublic class EmojiExtractEditText extends ExtractEditText { 437aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir private EmojiEditTextHelper mEmojiEditTextHelper; 447aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 457aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 467aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Prevent calling {@link #init(AttributeSet, int)} multiple times in case super() constructors 477aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * call other constructors. 487aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 497aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir private boolean mInitialized; 507aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 517aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context) { 527aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context); 53410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/); 547aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 557aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 567aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context, AttributeSet attrs) { 577aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context, attrs); 58410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, android.R.attr.editTextStyle, 0 /*defStyleRes*/); 597aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 607aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 617aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) { 627aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context, attrs, defStyleAttr); 63410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, defStyleAttr, 0 /*defStyleRes*/); 647aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 657aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 667aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir @TargetApi(Build.VERSION_CODES.LOLLIPOP) 677aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, 687aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir int defStyleRes) { 697aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context, attrs, defStyleAttr, defStyleRes); 70410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, defStyleAttr, defStyleRes); 717aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 727aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 73410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir private void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 747aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir if (!mInitialized) { 757aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir mInitialized = true; 767aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir final EditTextAttributeHelper attrHelper = new EditTextAttributeHelper(this, attrs, 77410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir defStyleAttr, defStyleRes); 787aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir setMaxEmojiCount(attrHelper.getMaxEmojiCount()); 797aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir setKeyListener(super.getKeyListener()); 807aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 817aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 827aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 837aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir @Override 847aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public void setKeyListener(android.text.method.KeyListener keyListener) { 857aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener)); 867aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 877aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 887aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir @Override 897aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 907aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir final InputConnection inputConnection = super.onCreateInputConnection(outAttrs); 917aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs); 927aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 937aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 947aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 957aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Set the maximum number of EmojiSpans to be added to a CharSequence. The number of spans in a 967aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * CharSequence affects the performance of the EditText insert/delete operations. Insert/delete 977aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * operations slow down as the number of spans increases. 987aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 997aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @param maxEmojiCount maximum number of EmojiSpans to be added to a single CharSequence, 1007aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * should be equal or greater than 0 1017aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @see EmojiCompat#process(CharSequence, int, int, int) 1027aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 1037aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public void setMaxEmojiCount(@IntRange(from = 0) int maxEmojiCount) { 1047aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir getEmojiEditTextHelper().setMaxEmojiCount(maxEmojiCount); 1057aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1067aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 1077aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 108410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * Sets whether to replace all emoji with {@link EmojiSpan}s. Default value is 109410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}. 110410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 111410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * @param replaceStrategy should be one of {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}, 112410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_NON_EXISTENT}, 113410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_ALL} 114410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir */ 115410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir public void setEmojiReplaceStrategy(@EmojiCompat.ReplaceStrategy int replaceStrategy) { 116410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir getEmojiEditTextHelper().setEmojiReplaceStrategy(replaceStrategy); 117410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir } 118410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir 119410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir /** 120410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * Returns whether to replace all emoji with {@link EmojiSpan}s. Default value is 121410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}. 122410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 123410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * @return one of {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}, 124410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_NON_EXISTENT}, 125410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_ALL} 126410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir */ 127410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir public int getEmojiReplaceStrategy() { 128410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir return getEmojiEditTextHelper().getEmojiReplaceStrategy(); 129410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir } 130410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir 131410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir /** 1327aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Returns the maximum number of EmojiSpans to be added to a CharSequence. 1337aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 1347aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @see #setMaxEmojiCount(int) 1357aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @see EmojiCompat#process(CharSequence, int, int, int) 1367aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 1377aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public int getMaxEmojiCount() { 1387aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir return getEmojiEditTextHelper().getMaxEmojiCount(); 1397aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1407aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 1417aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir private EmojiEditTextHelper getEmojiEditTextHelper() { 1427aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir if (mEmojiEditTextHelper == null) { 1437aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir mEmojiEditTextHelper = new EmojiEditTextHelper(this); 1447aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1457aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir return mEmojiEditTextHelper; 1467aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1477aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir} 148