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