115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root/*
215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Copyright (C) 2008 The Android Open Source Project
315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * you may not use this file except in compliance with the License.
615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * You may obtain a copy of the License at
715a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
815a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
915a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root *
1015a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Unless required by applicable law or agreed to in writing, software
1115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
1215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * See the License for the specific language governing permissions and
1415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * limitations under the License.
1515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root */
1615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.inputmethodservice;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.inputmethod.ExtractedText;
22a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatokimport android.view.inputmethod.InputMethodManager;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.EditText;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/***
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Specialization of {@link EditText} for showing and interacting with the
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * extracted text in a full-screen input method.
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ExtractEditText extends EditText {
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private InputMethodService mIME;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mSettingExtractedText;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ExtractEditText(Context context) {
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, null);
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ExtractEditText(Context context, AttributeSet attrs) {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super(context, attrs, com.android.internal.R.attr.editTextStyle);
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) {
42617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
43617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
44617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
45617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public ExtractEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
46617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setIME(InputMethodService ime) {
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIME = ime;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Start making changes that will not be reported to the client.  That
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is, {@link #onSelectionChanged(int, int)} will not result in sending
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the new selection to the client
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void startInternalChanges() {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSettingExtractedText += 1;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Finish making changes that will not be reported to the client.  That
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * is, {@link #onSelectionChanged(int, int)} will not result in sending
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the new selection to the client
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void finishInternalChanges() {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSettingExtractedText -= 1;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Implement just to keep track of when we are setting text from the
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * client (vs. seeing changes in ourself from the user).
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override public void setExtractedText(ExtractedText text) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSettingExtractedText++;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.setExtractedText(text);
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSettingExtractedText--;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Report to the underlying text editor about selection changes.
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override protected void onSelectionChanged(int selStart, int selEnd) {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSettingExtractedText == 0 && mIME != null && selStart >= 0 && selEnd >= 0) {
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIME.onExtractedSelectionChanged(selStart, selEnd);
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Redirect clicks to the IME for handling there.  First allows any
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * on click handler to run, though.
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override public boolean performClick() {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!super.performClick() && mIME != null) {
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIME.onExtractedTextClicked();
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override public boolean onTextContextMenuItem(int id) {
106459ac63adae54bafff2391f1f60c607f5deece4aGilles Debunne        if (mIME != null && mIME.onExtractTextContextMenuItem(id)) {
10714568c3f76cc4d3ad75dfd0206a3dc2130135c58Gilles Debunne            // Mode was started on Extracted, needs to be stopped here.
10814568c3f76cc4d3ad75dfd0206a3dc2130135c58Gilles Debunne            // Cut and paste will change the text, which stops selection mode.
10914568c3f76cc4d3ad75dfd0206a3dc2130135c58Gilles Debunne            if (id == android.R.id.copy) stopSelectionActionMode();
110459ac63adae54bafff2391f1f60c607f5deece4aGilles Debunne            return true;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.onTextContextMenuItem(id);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * We are always considered to be an input method target.
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
118e67b58a347109b444070a34e86e81ce119f266b3Gilles Debunne    @Override
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isInputMethodTarget() {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return true if the edit text is currently showing a scroll bar.
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasVerticalScrollBar() {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return computeVerticalScrollRange() > computeVerticalScrollExtent();
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Pretend like the window this view is in always has focus, so its
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * highlight and cursor will be displayed.
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override public boolean hasWindowFocus() {
135e67b58a347109b444070a34e86e81ce119f266b3Gilles Debunne        return this.isEnabled();
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Pretend like this view always has focus, so its
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * highlight and cursor will be displayed.
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override public boolean isFocused() {
143e67b58a347109b444070a34e86e81ce119f266b3Gilles Debunne        return this.isEnabled();
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Pretend like this view always has focus, so its
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * highlight and cursor will be displayed.
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override public boolean hasFocus() {
151e67b58a347109b444070a34e86e81ce119f266b3Gilles Debunne        return this.isEnabled();
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
153a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok
154a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok    /**
155a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok     * @hide
156a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok     */
157a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok    @Override protected void viewClicked(InputMethodManager imm) {
158a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok        // As an instance of this class is supposed to be owned by IMS,
159a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok        // and it has a reference to the IMS (the current IME),
160a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok        // we just need to call back its onViewClicked() here.
161a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok        // It should be good to avoid unnecessary IPCs by doing this as well.
162a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok        if (mIME != null) {
163a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok            mIME.onViewClicked(false);
164a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok        }
165a67a3cfc7c5db3b0a7710a75b57cd5360fce015asatok    }
16639ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne
16739ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    /**
168e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     * {@inheritDoc}
16939ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne     * @hide
17039ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne     */
17139ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    @Override
17239ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    protected void deleteText_internal(int start, int end) {
173e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // Do not call the super method.
174e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // This will change the source TextView instead, which will update the ExtractTextView.
17539ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne        mIME.onExtractedDeleteText(start, end);
17639ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    }
17739ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne
17839ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    /**
179e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     * {@inheritDoc}
18039ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne     * @hide
18139ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne     */
18239ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    @Override
18339ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    protected void replaceText_internal(int start, int end, CharSequence text) {
184e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // Do not call the super method.
185e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // This will change the source TextView instead, which will update the ExtractTextView.
18639ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne        mIME.onExtractedReplaceText(start, end, text);
18739ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne    }
18839ba6d9c4cf5a88d71edb800f3f48f85f61187c4Gilles Debunne
189e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    /**
190e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     * {@inheritDoc}
191e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     * @hide
192e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     */
193e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    @Override
194e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    protected void setSpan_internal(Object span, int start, int end, int flags) {
195e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // Do not call the super method.
196e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // This will change the source TextView instead, which will update the ExtractTextView.
197e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        mIME.onExtractedSetSpan(span, start, end, flags);
198e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    }
199e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne
200e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    /**
201e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     * {@inheritDoc}
202e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     * @hide
203e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne     */
204e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    @Override
205e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    protected void setCursorPosition_internal(int start, int end) {
206e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // Do not call the super method.
207e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        // This will change the source TextView instead, which will update the ExtractTextView.
208e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne        mIME.onExtractedSelectionChanged(start, end);
209e300be9c29b7915450ddb62f2957d312b52cfa32Gilles Debunne    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
211