1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package androidx.emoji.widget;
18
19import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20
21import android.content.Context;
22import android.inputmethodservice.ExtractEditText;
23import android.os.Build;
24import android.text.method.KeyListener;
25import android.util.AttributeSet;
26import android.view.inputmethod.EditorInfo;
27import android.view.inputmethod.InputConnection;
28
29import androidx.annotation.IntRange;
30import androidx.annotation.Nullable;
31import androidx.annotation.RequiresApi;
32import androidx.annotation.RestrictTo;
33import androidx.emoji.text.EmojiCompat;
34import androidx.emoji.text.EmojiSpan;
35
36/**
37 * ExtractEditText widget enhanced with emoji capability by using {@link EmojiEditTextHelper}.
38 * When used on devices running API 18 or below, this widget acts as a {@link ExtractEditText} and
39 * does not provide any emoji compatibility feature.
40 *
41 * @hide
42 */
43@RestrictTo(LIBRARY_GROUP)
44public class EmojiExtractEditText extends ExtractEditText {
45    private EmojiEditTextHelper mEmojiEditTextHelper;
46
47    /**
48     * Prevent calling {@link #init(AttributeSet, int)} multiple times in case super() constructors
49     * call other constructors.
50     */
51    private boolean mInitialized;
52
53    public EmojiExtractEditText(Context context) {
54        super(context);
55        init(null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
56    }
57
58    public EmojiExtractEditText(Context context, AttributeSet attrs) {
59        super(context, attrs);
60        init(attrs, android.R.attr.editTextStyle, 0 /*defStyleRes*/);
61    }
62
63    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) {
64        super(context, attrs, defStyleAttr);
65        init(attrs, defStyleAttr, 0 /*defStyleRes*/);
66    }
67
68    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
69    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr,
70            int defStyleRes) {
71        super(context, attrs, defStyleAttr, defStyleRes);
72        init(attrs, defStyleAttr, defStyleRes);
73    }
74
75    private void init(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
76        if (!mInitialized) {
77            mInitialized = true;
78            final EditTextAttributeHelper attrHelper = new EditTextAttributeHelper(this, attrs,
79                    defStyleAttr, defStyleRes);
80            setMaxEmojiCount(attrHelper.getMaxEmojiCount());
81            setKeyListener(super.getKeyListener());
82        }
83    }
84
85    @Override
86    public void setKeyListener(@Nullable KeyListener keyListener) {
87        if (keyListener != null) {
88            keyListener = getEmojiEditTextHelper().getKeyListener(keyListener);
89        }
90        super.setKeyListener(keyListener);
91    }
92
93    @Override
94    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
95        final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
96        return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
97    }
98
99    /**
100     * Set the maximum number of EmojiSpans to be added to a CharSequence. The number of spans in a
101     * CharSequence affects the performance of the EditText insert/delete operations. Insert/delete
102     * operations slow down as the number of spans increases.
103     *
104     * @param maxEmojiCount maximum number of EmojiSpans to be added to a single CharSequence,
105     *                      should be equal or greater than 0
106     * @see EmojiCompat#process(CharSequence, int, int, int)
107     */
108    public void setMaxEmojiCount(@IntRange(from = 0) int maxEmojiCount) {
109        getEmojiEditTextHelper().setMaxEmojiCount(maxEmojiCount);
110    }
111
112    /**
113     * Sets whether to replace all emoji with {@link EmojiSpan}s. Default value is
114     * {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}.
115     *
116     * @param replaceStrategy should be one of {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT},
117     *                        {@link EmojiCompat#REPLACE_STRATEGY_NON_EXISTENT},
118     *                        {@link EmojiCompat#REPLACE_STRATEGY_ALL}
119     */
120    public void setEmojiReplaceStrategy(@EmojiCompat.ReplaceStrategy int replaceStrategy) {
121        getEmojiEditTextHelper().setEmojiReplaceStrategy(replaceStrategy);
122    }
123
124    /**
125     * Returns whether to replace all emoji with {@link EmojiSpan}s. Default value is
126     * {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT}.
127     *
128     * @return one of {@link EmojiCompat#REPLACE_STRATEGY_DEFAULT},
129     *                        {@link EmojiCompat#REPLACE_STRATEGY_NON_EXISTENT},
130     *                        {@link EmojiCompat#REPLACE_STRATEGY_ALL}
131     */
132    public int getEmojiReplaceStrategy() {
133        return getEmojiEditTextHelper().getEmojiReplaceStrategy();
134    }
135
136    /**
137     * Returns the maximum number of EmojiSpans to be added to a CharSequence.
138     *
139     * @see #setMaxEmojiCount(int)
140     * @see EmojiCompat#process(CharSequence, int, int, int)
141     */
142    public int getMaxEmojiCount() {
143        return getEmojiEditTextHelper().getMaxEmojiCount();
144    }
145
146    private EmojiEditTextHelper getEmojiEditTextHelper() {
147        if (mEmojiEditTextHelper == null) {
148            mEmojiEditTextHelper = new EmojiEditTextHelper(this);
149        }
150        return mEmojiEditTextHelper;
151    }
152}
153