168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)package org.chromium.content.browser.input; 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import android.os.SystemClock; 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.text.Editable; 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.text.InputType; 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.text.Selection; 11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.text.TextUtils; 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.util.Log; 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.KeyEvent; 14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.View; 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.BaseInputConnection; 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.EditorInfo; 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.ExtractedText; 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import android.view.inputmethod.ExtractedTextRequest; 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport org.chromium.base.VisibleForTesting; 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/** 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * InputConnection is created by ContentView.onCreateInputConnection. 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * It then adapts android's IME to chrome's RenderWidgetHostView using the 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * native ImeAdapterAndroid via the class ImeAdapter. 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)public class AdapterInputConnection extends BaseInputConnection { 2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) private static final String TAG = "AdapterInputConnection"; 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private static final boolean DEBUG = false; 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Selection value should be -1 if not known. See EditorInfo.java for details. 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public static final int INVALID_SELECTION = -1; 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public static final int INVALID_COMPOSITION = -1; 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private final View mInternalView; 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private final ImeAdapter mImeAdapter; 3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) private final Editable mEditable; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private boolean mSingleLine; 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private int mNumNestedBatchEdits = 0; 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private int mLastUpdateSelectionStart = INVALID_SELECTION; 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private int mLastUpdateSelectionEnd = INVALID_SELECTION; 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private int mLastUpdateCompositionStart = INVALID_COMPOSITION; 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private int mLastUpdateCompositionEnd = INVALID_COMPOSITION; 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @VisibleForTesting 4923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) AdapterInputConnection(View view, ImeAdapter imeAdapter, Editable editable, 5023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) EditorInfo outAttrs) { 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super(view, true); 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mInternalView = view; 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mImeAdapter = imeAdapter; 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mImeAdapter.setInputConnection(this); 5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mEditable = editable; 5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // The editable passed in might have been in use by a prior keyboard and could have had 5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // prior composition spans set. To avoid keyboard conflicts, remove all composing spans 5823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // when taking ownership of an existing Editable. 5923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) removeComposingSpans(mEditable); 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mSingleLine = true; 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) | EditorInfo.IME_FLAG_NO_EXTRACT_UI; 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT; 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int inputType = imeAdapter.getTextInputType(); 676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) int inputFlags = imeAdapter.getTextInputFlags(); 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if ((inputFlags & imeAdapter.sTextInputFlagAutocompleteOff) != 0) { 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS; 706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (inputType == ImeAdapter.sTextInputTypeText) { 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Normal text field 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO; 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if ((inputFlags & imeAdapter.sTextInputFlagAutocorrectOff) == 0) { 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT; 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypeTextArea || 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) inputType == ImeAdapter.sTextInputTypeContentEditable) { 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TextArea or contenteditable. 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE 826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES; 836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if ((inputFlags & imeAdapter.sTextInputFlagAutocorrectOff) == 0) { 846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT; 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_NONE; 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mSingleLine = false; 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypePassword) { 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Password 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.inputType = InputType.TYPE_CLASS_TEXT 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD; 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO; 936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypeSearch) { 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Search 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_SEARCH; 966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypeUrl) { 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Url 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) outAttrs.inputType = InputType.TYPE_CLASS_TEXT 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) | InputType.TYPE_TEXT_VARIATION_URI; 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO; 1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypeEmail) { 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Email 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.inputType = InputType.TYPE_CLASS_TEXT 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS; 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO; 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypeTel) { 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Telephone 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Number and telephone do not have both a Tab key and an 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // action in default OSK, so set the action to NEXT 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.inputType = InputType.TYPE_CLASS_PHONE; 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT; 1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (inputType == ImeAdapter.sTextInputTypeNumber) { 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Number 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.inputType = InputType.TYPE_CLASS_NUMBER 1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch | InputType.TYPE_NUMBER_VARIATION_NORMAL 1160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch | InputType.TYPE_NUMBER_FLAG_DECIMAL; 117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT; 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 11923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) outAttrs.initialSelStart = Selection.getSelectionStart(mEditable); 12023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable); 12123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mLastUpdateSelectionStart = Selection.getSelectionStart(mEditable); 12223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mLastUpdateSelectionEnd = Selection.getSelectionEnd(mEditable); 12323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 12423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) Selection.setSelection(mEditable, outAttrs.initialSelStart, outAttrs.initialSelEnd); 12523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) updateSelectionIfRequired(); 126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Updates the AdapterInputConnection's internal representation of the text being edited and 1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * its selection and composition properties. The resulting Editable is accessible through the 1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * getEditable() method. If the text has not changed, this also calls updateSelection on the 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * InputMethodManager. 1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * 1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param text The String contents of the field being edited. 1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param selectionStart The character offset of the selection start, or the caret position if 1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * there is no selection. 1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param selectionEnd The character offset of the selection end, or the caret position if there 1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * is no selection. 1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param compositionStart The character offset of the composition start, or -1 if there is no 1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * composition. 1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * @param compositionEnd The character offset of the composition end, or -1 if there is no 1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * selection. 143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript). 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) @VisibleForTesting 1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public void updateState(String text, int selectionStart, int selectionEnd, int compositionStart, 147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int compositionEnd, boolean isNonImeChange) { 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) { 1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Log.w(TAG, "updateState [" + text + "] [" + selectionStart + " " + selectionEnd + "] [" 150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch + compositionStart + " " + compositionEnd + "] [" + isNonImeChange + "]"); 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // If this update is from the IME, no further state modification is necessary because the 153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // state should have been updated already by the IM framework directly. 154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!isNonImeChange) return; 1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces. 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) text = text.replace('\u00A0', ' '); 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selectionStart = Math.min(selectionStart, text.length()); 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selectionEnd = Math.min(selectionEnd, text.length()); 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) compositionStart = Math.min(compositionStart, text.length()); 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) compositionEnd = Math.min(compositionEnd, text.length()); 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 16423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) String prevText = mEditable.toString(); 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) boolean textUnchanged = prevText.equals(text); 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!textUnchanged) { 16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mEditable.replace(0, mEditable.length(), text); 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 17123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) Selection.setSelection(mEditable, selectionStart, selectionEnd); 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (compositionStart == compositionEnd) { 17423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) removeComposingSpans(mEditable); 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super.setComposingRegion(compositionStart, compositionEnd); 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) /** 18223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * @return Editable object which contains the state of current focused editable element. 18323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) */ 18423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) @Override 18523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) public Editable getEditable() { 18623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) return mEditable; 18723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) } 18823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) 18923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) /** 1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * Sends selection update to the InputMethodManager unless we are currently in a batch edit or 1914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * if the exact same selection and composition update was sent already. 1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) */ 1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private void updateSelectionIfRequired() { 1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (mNumNestedBatchEdits != 0) return; 19523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int selectionStart = Selection.getSelectionStart(mEditable); 19623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int selectionEnd = Selection.getSelectionEnd(mEditable); 19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int compositionStart = getComposingSpanStart(mEditable); 19823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int compositionEnd = getComposingSpanEnd(mEditable); 199c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Avoid sending update if we sent an exact update already previously. 200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (mLastUpdateSelectionStart == selectionStart && 201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateSelectionEnd == selectionEnd && 202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateCompositionStart == compositionStart && 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateCompositionEnd == compositionEnd) { 204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) { 2074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Log.w(TAG, "updateSelectionIfRequired [" + selectionStart + " " + selectionEnd + "] [" 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) + compositionStart + " " + compositionEnd + "]"); 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // updateSelection should be called every time the selection or composition changes 211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // if it happens not within a batch edit, or at the end of each top level batch edit. 212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) getInputMethodManagerWrapper().updateSelection(mInternalView, 213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selectionStart, selectionEnd, compositionStart, compositionEnd); 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateSelectionStart = selectionStart; 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateSelectionEnd = selectionEnd; 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateCompositionStart = compositionStart; 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mLastUpdateCompositionEnd = compositionEnd; 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int) 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean setComposingText(CharSequence text, int newCursorPosition) { 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPosition + "]"); 226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (maybePerformEmptyCompositionWorkaround(text)) return true; 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super.setComposingText(text, newCursorPosition); 2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 2296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition, false); 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#commitText(java.lang.CharSequence, int) 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean commitText(CharSequence text, int newCursorPosition) { 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]"); 238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (maybePerformEmptyCompositionWorkaround(text)) return true; 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super.commitText(text, newCursorPosition); 2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 2416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition, 2426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) text.length() > 0); 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#performEditorAction(int) 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean performEditorAction(int actionCode) { 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "performEditorAction [" + actionCode + "]"); 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (actionCode == EditorInfo.IME_ACTION_NEXT) { 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) restartInput(); 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Send TAB key event 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) long timeStampMs = SystemClock.uptimeMillis(); 255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mImeAdapter.sendSyntheticKeyEvent( 2566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ImeAdapter.sEventTypeRawKeyDown, timeStampMs, KeyEvent.KEYCODE_TAB, 0, 0); 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mImeAdapter.sendKeyEventWithKeyCode(KeyEvent.KEYCODE_ENTER, 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) | KeyEvent.FLAG_EDITOR_ACTION); 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#performContextMenuAction(int) 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean performContextMenuAction(int id) { 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "performContextMenuAction [" + id + "]"); 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) switch (id) { 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case android.R.id.selectAll: 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return mImeAdapter.selectAll(); 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case android.R.id.cut: 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return mImeAdapter.cut(); 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case android.R.id.copy: 277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return mImeAdapter.copy(); 278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) case android.R.id.paste: 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return mImeAdapter.paste(); 280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) default: 281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#getExtractedText(android.view.inputmethod.ExtractedTextRequest, 287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * int) 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "getExtractedText"); 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExtractedText et = new ExtractedText(); 29323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) et.text = mEditable.toString(); 29423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) et.partialEndOffset = mEditable.length(); 29523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) et.selectionStart = Selection.getSelectionStart(mEditable); 29623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) et.selectionEnd = Selection.getSelectionEnd(mEditable); 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0; 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return et; 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#beginBatchEdit() 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean beginBatchEdit() { 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "beginBatchEdit [" + (mNumNestedBatchEdits == 0) + "]"); 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mNumNestedBatchEdits++; 3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#endBatchEdit() 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 315c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean endBatchEdit() { 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (mNumNestedBatchEdits == 0) return false; 317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) --mNumNestedBatchEdits; 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "endBatchEdit [" + (mNumNestedBatchEdits == 0) + "]"); 3194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (mNumNestedBatchEdits == 0) updateSelectionIfRequired(); 3204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return mNumNestedBatchEdits != 0; 321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#deleteSurroundingText(int, int) 325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public boolean deleteSurroundingText(int beforeLength, int afterLength) { 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) { 329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLength + "]"); 330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int originalBeforeLength = beforeLength; 332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int originalAfterLength = afterLength; 33323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int availableBefore = Selection.getSelectionStart(mEditable); 33423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int availableAfter = mEditable.length() - Selection.getSelectionEnd(mEditable); 335d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) beforeLength = Math.min(beforeLength, availableBefore); 336d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) afterLength = Math.min(afterLength, availableAfter); 337d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) super.deleteSurroundingText(beforeLength, afterLength); 3384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 339116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 340116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // For single-char deletion calls |ImeAdapter.sendKeyEventWithKeyCode| with the real key 341116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // code. For multi-character deletion, executes deletion by calling 342116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // |ImeAdapter.deleteSurroundingText| and sends synthetic key events with a dummy key code. 343116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int keyCode = KeyEvent.KEYCODE_UNKNOWN; 344116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (originalBeforeLength == 1 && originalAfterLength == 0) 345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch keyCode = KeyEvent.KEYCODE_DEL; 346116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch else if (originalBeforeLength == 0 && originalAfterLength == 1) 347116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch keyCode = KeyEvent.KEYCODE_FORWARD_DEL; 348116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 349116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch boolean result = true; 350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (keyCode == KeyEvent.KEYCODE_UNKNOWN) { 351116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch result = mImeAdapter.sendSyntheticKeyEvent( 3526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ImeAdapter.sEventTypeRawKeyDown, SystemClock.uptimeMillis(), keyCode, 0, 0); 353116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch result &= mImeAdapter.deleteSurroundingText(beforeLength, afterLength); 354116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch result &= mImeAdapter.sendSyntheticKeyEvent( 3556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ImeAdapter.sEventTypeKeyUp, SystemClock.uptimeMillis(), keyCode, 0, 0); 356116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } else { 357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch mImeAdapter.sendKeyEventWithKeyCode( 358116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch keyCode, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); 359116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 360116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return result; 361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent) 365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean sendKeyEvent(KeyEvent event) { 3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (DEBUG) { 3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Log.w(TAG, "sendKeyEvent [" + event.getAction() + "] [" + event.getKeyCode() + "]"); 3704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // If this is a key-up, and backspace/del or if the key has a character representation, 372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // need to update the underlying Editable (i.e. the local representation of the text 373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // being edited). 374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (event.getAction() == KeyEvent.ACTION_UP) { 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) { 3764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) deleteSurroundingText(1, 0); 3774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) { 3794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) deleteSurroundingText(0, 1); 3804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int unicodeChar = event.getUnicodeChar(); 383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (unicodeChar != 0) { 38423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int selectionStart = Selection.getSelectionStart(mEditable); 38523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int selectionEnd = Selection.getSelectionEnd(mEditable); 386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (selectionStart > selectionEnd) { 387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int temp = selectionStart; 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selectionStart = selectionEnd; 389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) selectionEnd = temp; 390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 39123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) mEditable.replace(selectionStart, selectionEnd, 392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Character.toString((char) unicodeChar)); 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 395424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } else if (event.getAction() == KeyEvent.ACTION_DOWN) { 396424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed. 397424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) { 398424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) beginBatchEdit(); 399424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) finishComposingText(); 400424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) mImeAdapter.translateAndSendNativeEvents(event); 401424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) endBatchEdit(); 402424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) return true; 4034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) { 4044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 4054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) { 4064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return true; 407424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mImeAdapter.translateAndSendNativeEvents(event); 410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#finishComposingText() 415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean finishComposingText() { 418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "finishComposingText"); 41923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) { 420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 422a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super.finishComposingText(); 4244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 4257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch mImeAdapter.finishComposingText(); 426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#setSelection(int, int) 432c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean setSelection(int start, int end) { 43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (DEBUG) Log.w(TAG, "setSelection [" + start + " " + end + "]"); 43623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int textLength = mEditable.length(); 43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (start < 0 || end < 0 || start > textLength || end > textLength) return true; 438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super.setSelection(start, end); 4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return mImeAdapter.setEditableSelectionOffsets(start, end); 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text 445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * state is no longer what the IME has and that it needs to be updated. 446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void restartInput() { 448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "restartInput"); 449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) getInputMethodManagerWrapper().restartInput(mInternalView); 450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) mNumNestedBatchEdits = 0; 451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) /** 454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @see BaseInputConnection#setComposingRegion(int, int) 455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */ 456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @Override 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public boolean setComposingRegion(int start, int end) { 458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]"); 45923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int textLength = mEditable.length(); 460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int a = Math.min(start, end); 461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int b = Math.max(start, end); 462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (a < 0) a = 0; 463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (b < 0) b = 0; 46458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (a > textLength) a = textLength; 46558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (b > textLength) b = textLength; 466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (a == b) { 46823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) removeComposingSpans(mEditable); 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) super.setComposingRegion(a, b); 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 4724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) updateSelectionIfRequired(); 4735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 4745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CharSequence regionText = null; 4755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (b > a) { 4766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) regionText = mEditable.subSequence(a, b); 4775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 4785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return mImeAdapter.setComposingRegion(regionText, a, b); 479c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) boolean isActive() { 482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return getInputMethodManagerWrapper().isActive(mInternalView); 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private InputMethodManagerWrapper getInputMethodManagerWrapper() { 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return mImeAdapter.getInputMethodManagerWrapper(); 487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 48868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 489cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) /** 490cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * This method works around the issue crbug.com/373934 where Blink does not cancel 491cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * the composition when we send a commit with the empty text. 492cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 493cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * TODO(aurimas) Remove this once crbug.com/373934 is fixed. 494cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * 495cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @param text Text that software keyboard requested to commit. 496cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * @return Whether the workaround was performed. 497cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */ 498cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private boolean maybePerformEmptyCompositionWorkaround(CharSequence text) { 499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int selectionStart = Selection.getSelectionStart(mEditable); 500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int selectionEnd = Selection.getSelectionEnd(mEditable); 501cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int compositionStart = getComposingSpanStart(mEditable); 502cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int compositionEnd = getComposingSpanEnd(mEditable); 503cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (TextUtils.isEmpty(text) && (selectionStart == selectionEnd) 504cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) && compositionStart != INVALID_COMPOSITION 505cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) && compositionEnd != INVALID_COMPOSITION) { 506cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) beginBatchEdit(); 507cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) finishComposingText(); 508cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int selection = Selection.getSelectionStart(mEditable); 509cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) deleteSurroundingText(selection - compositionStart, selection - compositionEnd); 510cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) endBatchEdit(); 511cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return true; 512cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 513cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return false; 514cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 515cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 51668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) @VisibleForTesting 51768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) static class ImeState { 51868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public final String text; 51968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public final int selectionStart; 52068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public final int selectionEnd; 52168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public final int compositionStart; 52268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public final int compositionEnd; 52368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 52468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public ImeState(String text, int selectionStart, int selectionEnd, 52568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) int compositionStart, int compositionEnd) { 52668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) this.text = text; 52768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) this.selectionStart = selectionStart; 52868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) this.selectionEnd = selectionEnd; 52968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) this.compositionStart = compositionStart; 53068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) this.compositionEnd = compositionEnd; 53168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 53268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 53368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 53468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) @VisibleForTesting 53568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ImeState getImeStateForTesting() { 53623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) String text = mEditable.toString(); 53723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int selectionStart = Selection.getSelectionStart(mEditable); 53823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int selectionEnd = Selection.getSelectionEnd(mEditable); 53923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int compositionStart = getComposingSpanStart(mEditable); 54023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) int compositionEnd = getComposingSpanEnd(mEditable); 54168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) return new ImeState(text, selectionStart, selectionEnd, compositionStart, compositionEnd); 54268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) } 543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 544