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