1f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir/* 2f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * Copyright (C) 2017 The Android Open Source Project 3f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * 4f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * Licensed under the Apache License, Version 2.0 (the "License"); 5f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * you may not use this file except in compliance with the License. 6f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * You may obtain a copy of the License at 7f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * 8f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * http://www.apache.org/licenses/LICENSE-2.0 9f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * 10f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * Unless required by applicable law or agreed to in writing, software 11f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * distributed under the License is distributed on an "AS IS" BASIS, 12f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * See the License for the specific language governing permissions and 14f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir * limitations under the License. 15f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir */ 16ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.emoji.widget; 17f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 18f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.content.Context; 19f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.os.Build; 2001e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinirimport android.text.method.KeyListener; 21f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.util.AttributeSet; 22f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.view.inputmethod.EditorInfo; 23f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.view.inputmethod.InputConnection; 24f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirimport android.widget.EditText; 25f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 2638746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.annotation.IntRange; 2738746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.annotation.Nullable; 2838746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.annotation.RequiresApi; 2938746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikasimport androidx.emoji.text.EmojiCompat; 3038746a682208c764867ffe4415d0b62fb22b5b9aAurimas Liutikas 31f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir/** 3277b5c5b734f9f665577d1e3d178615db43ae1d4fSiyamed Sinir * EditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}. When used 3377b5c5b734f9f665577d1e3d178615db43ae1d4fSiyamed Sinir * on devices running API 18 or below, this widget acts as a regular {@link EditText}. 34410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 35ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * @attr ref androidx.emoji.R.styleable#EmojiEditText_maxEmojiCount 36f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir */ 37f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinirpublic class EmojiEditText extends EditText { 38f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir private EmojiEditTextHelper mEmojiEditTextHelper; 397aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir 407aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir /** 41410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * Prevent calling {@link #init(AttributeSet, int, int)} multiple times in case super() 42410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * constructors call other constructors. 437aee4cbe81e43d7cfcb271809caefccfe6b86a89Siyamed Sinir */ 44f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir private boolean mInitialized; 45f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 46f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir public EmojiEditText(Context context) { 47f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir super(context); 48410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/); 49f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 50f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 51f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir public EmojiEditText(Context context, AttributeSet attrs) { 52f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir super(context, attrs); 53410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, android.R.attr.editTextStyle, 0 /*defStyleRes*/); 54f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 55f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 56f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) { 57f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir super(context, attrs, defStyleAttr); 58410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, defStyleAttr, 0 /*defStyleRes*/); 59f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 60f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 61d8a34479f81c58db620b26ab31ee2ca5e811059dAurimas Liutikas @RequiresApi(Build.VERSION_CODES.LOLLIPOP) 62f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 63f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir super(context, attrs, defStyleAttr, defStyleRes); 64410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir init(attrs, defStyleAttr, defStyleRes); 65f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 66f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 67410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir private void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 68f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir if (!mInitialized) { 69f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir mInitialized = true; 70d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir final EditTextAttributeHelper attrHelper = new EditTextAttributeHelper(this, attrs, 71410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir defStyleAttr, defStyleRes); 72d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir setMaxEmojiCount(attrHelper.getMaxEmojiCount()); 73d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir setKeyListener(super.getKeyListener()); 74f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 75f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 76f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 77f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir @Override 7801e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir public void setKeyListener(@Nullable KeyListener keyListener) { 7901e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir if (keyListener != null) { 8001e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir keyListener = getEmojiEditTextHelper().getKeyListener(keyListener); 8101e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir } 8201e10075570e97717b9288f5e5a9d9341f79db17Siyamed Sinir super.setKeyListener(keyListener); 83f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 84f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 85f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir @Override 86f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 87d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir final InputConnection inputConnection = super.onCreateInputConnection(outAttrs); 88f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs); 89f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 90f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir 91d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir /** 92d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * Set the maximum number of EmojiSpans to be added to a CharSequence. The number of spans in a 93d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * CharSequence affects the performance of the EditText insert/delete operations. Insert/delete 94d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * operations slow down as the number of spans increases. 95d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * 96d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * @param maxEmojiCount maximum number of EmojiSpans to be added to a single CharSequence, 97d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * should be equal or greater than 0 98d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * 99d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * @see EmojiCompat#process(CharSequence, int, int, int) 100410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 101ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * @attr ref androidx.emoji.R.styleable#EmojiEditText_maxEmojiCount 102d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir */ 103d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir public void setMaxEmojiCount(@IntRange(from = 0) int maxEmojiCount) { 104d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir getEmojiEditTextHelper().setMaxEmojiCount(maxEmojiCount); 105d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir } 106d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir 107d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir /** 108d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * Returns the maximum number of EmojiSpans to be added to a CharSequence. 109d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * 110d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * @see #setMaxEmojiCount(int) 111d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir * @see EmojiCompat#process(CharSequence, int, int, int) 112410ea048366f492ff9908c1dbe91160da87792fcSiyamed Sinir * 113ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * @attr ref androidx.emoji.R.styleable#EmojiEditText_maxEmojiCount 114d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir */ 115d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir public int getMaxEmojiCount() { 116d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir return getEmojiEditTextHelper().getMaxEmojiCount(); 117d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir } 118d6e62a9d119a07f4d2bd686f357d8a667085fe71Siyamed Sinir 119f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir private EmojiEditTextHelper getEmojiEditTextHelper() { 120f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir if (mEmojiEditTextHelper == null) { 121f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir mEmojiEditTextHelper = new EmojiEditTextHelper(this); 122f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 123f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir return mEmojiEditTextHelper; 124f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir } 125f8ec169d022fbed42fd82091d24c45f3767cdfe7Siyamed Sinir} 126