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 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.emoji.widget; 187aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 19ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; 207aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 217aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.content.Context; 227aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.inputmethodservice.ExtractEditText; 237aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirimport android.os.Build; 2438746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport android.text.method.KeyListener; 2538746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport android.util.AttributeSet; 2638746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport android.view.inputmethod.EditorInfo; 2738746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport android.view.inputmethod.InputConnection; 2838746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikas 29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.IntRange; 30ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable; 31ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RequiresApi; 32ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.RestrictTo; 33ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.emoji.text.EmojiCompat; 34ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.emoji.text.EmojiSpan; 357aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 367aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir/** 377aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * ExtractEditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}. 387aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * When used on devices running API 18 or below, this widget acts as a {@link ExtractEditText} and 397aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * does not provide any emoji compatibility feature. 407aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 417aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @hide 427aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 437aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir@RestrictTo(LIBRARY_GROUP) 447aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinirpublic class EmojiExtractEditText extends ExtractEditText { 457aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir private EmojiEditTextHelper mEmojiEditTextHelper; 467aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 477aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 487aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Prevent calling {@link #init(AttributeSet, int)} multiple times in case super() constructors 497aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * call other constructors. 507aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 517aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir private boolean mInitialized; 527aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 537aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context) { 547aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context); 55410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/); 567aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 577aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 587aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context, AttributeSet attrs) { 597aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context, attrs); 60410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, android.R.attr.editTextStyle, 0 /*defStyleRes*/); 617aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 627aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 637aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) { 647aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context, attrs, defStyleAttr); 65410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, defStyleAttr, 0 /*defStyleRes*/); 667aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 677aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 68d8a34479f81c58db620b26ab31ee2ca5e811059dAurimas Liutikas @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 697aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, 707aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir int defStyleRes) { 717aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir super(context, attrs, defStyleAttr, defStyleRes); 72410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, defStyleAttr, defStyleRes); 737aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 747aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 75410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir private void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 767aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir if (!mInitialized) { 777aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir mInitialized = true; 787aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir final EditTextAttributeHelper attrHelper = new EditTextAttributeHelper(this, attrs, 79410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir defStyleAttr, defStyleRes); 807aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir setMaxEmojiCount(attrHelper.getMaxEmojiCount()); 817aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir setKeyListener(super.getKeyListener()); 827aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 837aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 847aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 857aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir @Override 8601e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir public void setKeyListener(@Nullable KeyListener keyListener) { 8701e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir if (keyListener != null) { 8801e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir keyListener = getEmojiEditTextHelper().getKeyListener(keyListener); 8901e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir } 9001e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir super.setKeyListener(keyListener); 917aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 927aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 937aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir @Override 947aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 957aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir final InputConnection inputConnection = super.onCreateInputConnection(outAttrs); 967aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs); 977aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 987aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 997aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 1007aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Set the maximum number of EmojiSpans to be added to a CharSequence. The number of spans in a 1017aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * CharSequence affects the performance of the EditText insert/delete operations. Insert/delete 1027aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * operations slow down as the number of spans increases. 1037aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 1047aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @param maxEmojiCount maximum number of EmojiSpans to be added to a single CharSequence, 1057aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * should be equal or greater than 0 1067aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @see EmojiCompat#process(CharSequence, int, int, int) 1077aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 1087aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public void setMaxEmojiCount(@IntRange(from = 0) int maxEmojiCount) { 1097aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir getEmojiEditTextHelper().setMaxEmojiCount(maxEmojiCount); 1107aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1117aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 1127aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 113410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * Sets whether to replace all emoji with {@link EmojiSpan}s. Default value is 114410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}. 115410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 116410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * @param replaceStrategy should be one of {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}, 117410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_NON_EXISTENT}, 118410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_ALL} 119410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir */ 120410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir public void setEmojiReplaceStrategy(@EmojiCompat.ReplaceStrategy int replaceStrategy) { 121410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir getEmojiEditTextHelper().setEmojiReplaceStrategy(replaceStrategy); 122410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir } 123410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir 124410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir /** 125410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * Returns whether to replace all emoji with {@link EmojiSpan}s. Default value is 126410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}. 127410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 128410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * @return one of {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}, 129410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_NON_EXISTENT}, 130410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * {@link EmojiCompat#REPLACE_STRATEGY_ALL} 131410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir */ 132410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir public int getEmojiReplaceStrategy() { 133410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir return getEmojiEditTextHelper().getEmojiReplaceStrategy(); 134410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir } 135410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir 136410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir /** 1377aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * Returns the maximum number of EmojiSpans to be added to a CharSequence. 1387aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * 1397aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @see #setMaxEmojiCount(int) 1407aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir * @see EmojiCompat#process(CharSequence, int, int, int) 1417aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 1427aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir public int getMaxEmojiCount() { 1437aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir return getEmojiEditTextHelper().getMaxEmojiCount(); 1447aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1457aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 1467aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir private EmojiEditTextHelper getEmojiEditTextHelper() { 1477aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir if (mEmojiEditTextHelper == null) { 1487aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir mEmojiEditTextHelper = new EmojiEditTextHelper(this); 1497aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1507aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir return mEmojiEditTextHelper; 1517aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir } 1527aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir} 153