LatinIME.java revision 243e370fcb1c2cb8608614206075ecdbe79a6372
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 191cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII; 201cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE; 211cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT; 221cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog; 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver; 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface; 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent; 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter; 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences; 30b224b60c94d85f30de93f66685adf06e662618c0Jean Chalardimport android.content.pm.ApplicationInfo; 31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration; 3236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources; 33c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.graphics.Rect; 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager; 36123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug; 3881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaokaimport android.os.IBinder; 39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 41bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager; 43e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils; 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter; 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer; 484e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyCharacterMap; 494e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyEvent; 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 518e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup; 52c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.view.ViewGroup.LayoutParams; 53cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokaimport android.view.ViewParent; 5413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.Window; 5513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.WindowManager; 56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo; 5796fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasaimport android.view.inputmethod.CorrectionInfo; 58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo; 599cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 60c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils; 628d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 63c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils; 64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper; 651fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils; 66c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 67c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 686b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 69c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 70f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 71c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView; 7216c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaokaimport com.android.inputmethod.latin.LocaleUtils.RunInLocale; 73c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 748c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionsView; 75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 76466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor; 77466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter; 784ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalardimport java.util.ArrayList; 79466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale; 80466741d8a78965b8509bf527344f289e50873092Mike LeBeau 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard. 83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 8413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokapublic class LatinIME extends InputMethodService implements KeyboardActionListener, 85b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard SuggestionsView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener { 868efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka private static final String TAG = LatinIME.class.getSimpleName(); 87409220583333bdf06290dd9fd42f91b5c0d1b11asatok private static final boolean TRACE = false; 889e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka private static boolean DEBUG; 89a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 909e347d3d448e48229c46aad394ec9bd60cd5807bsatok private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; 91fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa 92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // How many continuous deletes at which to start deleting at a higher speed. 93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int DELETE_ACCELERATE_AT = 20; 94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Key events coming any faster than this are long-presses. 95d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani private static final int QUICK_PRESS = 200; 96a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 9759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private static final int PENDING_IMS_CALLBACK_DURATION = 800; 98055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 99cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /** 100cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * The name of the scheme used by the Package Manager to warn of a new package installation, 101cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * replacement or removal. 102cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard */ 103cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private static final String SCHEME_PACKAGE = "package"; 104cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 105fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_NONE = 0; 106120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Double space: the state where the user pressed space twice quickly, which LatinIME 107120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // resolved as period-space. Undoing this converts the period to a space. 108fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_DOUBLE = 1; 109b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip 110b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // have just been swapped. Undoing this swaps them back; the space is still considered weak. 111120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; 112fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak 113fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // spaces happen when the user presses space, accepting the current suggestion (whether 114fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // it's an auto-correction or not). 115fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_WEAK = 3; 116fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom space: a not-yet-inserted space that should get inserted on the next input, 117fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // character provided it's not a separator. If it's a separator, the phantom space is dropped. 118fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom spaces happen when a user chooses a word from the suggestion strip. 119fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_PHANTOM = 4; 120120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 121120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Current space state of the input method. This can be any of the above constants. 122120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private int mSpaceState; 123126698fdd256a2e3734634d3b923cabd800064baJean Chalard 124297e6d590bd957577c335aa8713a786145a70288Jean Chalard private SettingsValues mCurrentSettings; 12580b66bb166f7f45adfcadcb84788477df9930828Jean Chalard private InputAttributes mInputAttributes; 12617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 127d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka private View mExtractArea; 128abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka private View mKeyPreviewBackingView; 129913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private View mSuggestionsContainer; 130913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private SuggestionsView mSuggestionsView; 131816a8a0fd85ca0327436f8bd1cfa6928600ebc5dJean Chalard /* package for tests */ Suggest mSuggest; 1321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private CompletionInfo[] mApplicationSpecifiedCompletions; 133b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard private ApplicationInfo mTargetApplicationInfo; 134a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 135610f1dc8553cf2ed97e763a06a19380c4a6cd636satok private InputMethodManagerCompatWrapper mImm; 1362fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private Resources mResources; 1372fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private SharedPreferences mPrefs; 138109728193e45262099cbf88d8d6fcc4ed05240caJean Chalard /* package for tests */ final KeyboardSwitcher mKeyboardSwitcher; 13989ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard private final SubtypeSwitcher mSubtypeSwitcher; 14081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private boolean mShouldSwitchToLastSubtype = true; 141a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1426a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka private boolean mIsMainDictionaryAvailable; 14367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private UserBinaryDictionary mUserDictionary; 1449ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard private UserHistoryDictionary mUserHistoryDictionary; 14588562bec54658840dcce352127bdc15705c20a89Jean Chalard private boolean mIsUserDictionaryAvailable; 14636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 1472692a8700737d8eed268039aa27b22a31669da08Jean Chalard private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 1489318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa private WordComposer mWordComposer = new WordComposer(); 1495475b38328171a0841ae18074bd45380ec567e90Jean Chalard private RichInputConnection mConnection = new RichInputConnection(); 150409220583333bdf06290dd9fd42f91b5c0d1b11asatok 151979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Keep track of the last selection range to decide if we need to show word alternatives 15277da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private static final int NOT_A_CURSOR_POSITION = -1; 15377da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionStart = NOT_A_CURSOR_POSITION; 15477da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; 155979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1564733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't 1574733609947c0ec74e460bd714fffca0518ade93aJean Chalard // "expect" it, it means the user actually moved the cursor. 1584733609947c0ec74e460bd714fffca0518ade93aJean Chalard private boolean mExpectingUpdateSelection; 159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mDeleteCount; 160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private long mLastKeyTime; 161a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 162564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard private AudioAndHapticFeedbackManager mFeedbackManager; 16328f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 16438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Member variables for remembering the current device orientation. 16538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka private int mDisplayOrientation; 16638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 167cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Object for reacting to adding/removing a dictionary pack. 168cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private BroadcastReceiver mDictionaryPackInstallReceiver = 169cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard new DictionaryPackInstallBroadcastReceiver(this); 170cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 171dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Keeps track of most recently inserted text (multi-character key) for reverting 172dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani private CharSequence mEnteredText; 173dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 17470852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard private boolean mIsAutoCorrectionIndicatorOn; 175604d80c67185954d4691ac775be59c499eee3b1csatok 17613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka private AlertDialog mOptionsDialog; 17713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 1784f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public final UIHandler mHandler = new UIHandler(this); 179d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 1804f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { 18145f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_UPDATE_SHIFT_STATE = 1; 1824c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_SPACE_TYPED = 4; 1834c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_SET_BIGRAM_PREDICTIONS = 5; 1844c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_PENDING_IMS_CALLBACK = 6; 1854c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTIONS = 7; 1864c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka 18710dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateSuggestions; 18810dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateShiftState; 18910dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private long mDoubleSpacesTurnIntoPeriodTimeout; 19038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 1914f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UIHandler(LatinIME outerInstance) { 1924f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 19310dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka } 194175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 19510dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka public void onCreate() { 19610dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka final Resources res = getOuterInstance().getResources(); 197175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateSuggestions = 198175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_suggestions); 199175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateShiftState = 200175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_shift_state); 201175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger( 202175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_double_spaces_turn_into_period_timeout); 2034f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 2044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void handleMessage(Message msg) { 2074f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 2084f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; 209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 210d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SUGGESTIONS: 2114f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.updateSuggestions(); 212d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 213d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SHIFT_STATE: 214de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka switcher.updateShiftState(); 215d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 216cb3320179d39a7983874697a0aa428b127675c9dJean Chalard case MSG_SET_BIGRAM_PREDICTIONS: 2174f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.updateBigramPredictions(); 21889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard break; 219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 221d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 222d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void postUpdateSuggestions() { 223d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTIONS); 224175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), mDelayUpdateSuggestions); 225d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 226d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 227d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateSuggestions() { 228d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTIONS); 229d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 230d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 231d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public boolean hasPendingUpdateSuggestions() { 232d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka return hasMessages(MSG_UPDATE_SUGGESTIONS); 233d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 234d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 235beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void postUpdateShiftState() { 236d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 237175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); 238d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 239d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 240d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateShiftState() { 241d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 242d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 243d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 244cb3320179d39a7983874697a0aa428b127675c9dJean Chalard public void postUpdateBigramPredictions() { 245cb3320179d39a7983874697a0aa428b127675c9dJean Chalard removeMessages(MSG_SET_BIGRAM_PREDICTIONS); 246175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS), mDelayUpdateSuggestions); 24789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 24889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 249cb3320179d39a7983874697a0aa428b127675c9dJean Chalard public void cancelUpdateBigramPredictions() { 250cb3320179d39a7983874697a0aa428b127675c9dJean Chalard removeMessages(MSG_SET_BIGRAM_PREDICTIONS); 25189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 25289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 253fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void startDoubleSpacesTimer() { 254fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka removeMessages(MSG_SPACE_TYPED); 255175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout); 256fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 257fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 258fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void cancelDoubleSpacesTimer() { 259fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka removeMessages(MSG_SPACE_TYPED); 260fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 261fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 262fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public boolean isAcceptingDoubleSpaces() { 263fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka return hasMessages(MSG_SPACE_TYPED); 264fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 26538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 26659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Working variables for the following methods. 26759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mIsOrientationChanging; 2685fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard private boolean mPendingSuccessiveImsCallback; 26959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingStartInput; 27059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInputView; 27159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInput; 272e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private EditorInfo mAppliedEditorInfo; 27359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 27459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void startOrientationChanging() { 275dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka removeMessages(MSG_PENDING_IMS_CALLBACK); 276dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka resetPendingImsCallback(); 27759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = true; 278055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 279f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka if (latinIme.isInputViewShown()) { 280f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka latinIme.mKeyboardSwitcher.saveKeyboardState(); 281f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka } 28259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 28359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 28459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void resetPendingImsCallback() { 28559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = false; 28659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = false; 28759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = false; 28859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 28959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 290e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void executePendingImsCallback(LatinIME latinIme, EditorInfo editorInfo, 29159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka boolean restarting) { 29259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInputView) 29359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(mHasPendingFinishInput); 29459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInput) 29559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 29659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingStartInput) 297e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 29859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka resetPendingImsCallback(); 29959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 30059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 301e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 30259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 30359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the second onStartInput after orientation changed. 30459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = true; 30559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 30659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mIsOrientationChanging && restarting) { 30759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // This is the first onStartInput after orientation changed. 30859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = false; 3095fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = true; 31059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 31159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 312e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 313e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 314055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 315055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 316055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 317e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 3186b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK) 3196b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { 320e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // Typically this is the second onStartInputView after orientation changed. 321e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 322e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } else { 3235fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard if (mPendingSuccessiveImsCallback) { 324e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // This is the first onStartInputView after orientation changed. 3255fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = false; 326e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 327e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), 328e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka PENDING_IMS_CALLBACK_DURATION); 329e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 330e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 331e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 332e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputViewInternal(editorInfo, restarting); 333e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = editorInfo; 334e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 33559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 33659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 33759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 33859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 33959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInputView after orientation changed. 34059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = true; 34159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 34259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 34359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(finishingInput); 344e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = null; 34538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 34638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 347ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka 34859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 34959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 35059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInput after orientation changed. 35159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = true; 35259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 35359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 35459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka executePendingImsCallback(latinIme, null, false); 35559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 356ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 357ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 35838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 35938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 36089ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard public LatinIME() { 36189ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard super(); 36289ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 36389ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mKeyboardSwitcher = KeyboardSwitcher.getInstance(); 36489ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard } 36589ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard 3667e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 3677e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka public void onCreate() { 36827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 36927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa mPrefs = prefs; 37027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa LatinImeLogger.init(this, prefs); 371c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 37207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge ResearchLogger.getInstance().init(this, prefs); 373c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa } 374bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka InputMethodManagerCompatWrapper.init(this); 375ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka SubtypeSwitcher.init(this); 37627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa KeyboardSwitcher.init(this, prefs); 3772ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka AccessibilityUtils.init(this); 378363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onCreate(); 380363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 381bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka mImm = InputMethodManagerCompatWrapper.getInstance(); 38210dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka mHandler.onCreate(); 3839e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka DEBUG = LatinImeLogger.sDBG; 384363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 385363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka final Resources res = getResources(); 386363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka mResources = res; 387fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard 38828f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa loadSettings(); 38928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 390297e6d590bd957577c335aa8713a786145a70288Jean Chalard ImfUtils.setAdditionalInputMethodSubtypes(this, mCurrentSettings.getAdditionalSubtypes()); 391f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka 3929502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 393979f8690967ff5409fe18f5085858ccdb8e0ccf1satok boolean tryGC = true; 3949502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 395979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 3960ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 397979f8690967ff5409fe18f5085858ccdb8e0ccf1satok tryGC = false; 398979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (OutOfMemoryError e) { 3999502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e); 400979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 401979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 402979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 403f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = res.getConfiguration().orientation; 404b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 405cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Register to receive ringer mode change and network state change. 406cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Also receive installation and removal of a dictionary pack. 407123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final IntentFilter filter = new IntentFilter(); 408123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 40921af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 410923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project registerReceiver(mReceiver, filter); 411cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 412cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final IntentFilter packageFilter = new IntentFilter(); 413cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 414cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 415cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addDataScheme(SCHEME_PACKAGE); 416cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, packageFilter); 417646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard 418646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard final IntentFilter newDictFilter = new IntentFilter(); 419646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard newDictFilter.addAction( 420646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION); 421646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); 422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 42336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 42417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // Has to be package-visible for unit tests 42517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard /* package */ void loadSettings() { 4264f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 4274f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 42817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 42916c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { 43016c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka @Override 43116c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka protected SettingsValues job(Resources res) { 4324b9e6ee6fb408e2793e9ead5de2d6b45270d1f0dJean Chalard return new SettingsValues(mPrefs, mInputAttributes, LatinIME.this); 43316c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka } 43416c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka }; 435297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale()); 436297e6d590bd957577c335aa8713a786145a70288Jean Chalard mFeedbackManager = new AudioAndHapticFeedbackManager(this, mCurrentSettings); 43714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); 43817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 43917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 4400ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private void initSuggest() { 4416a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 4426a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final String localeStr = subtypeLocale.toString(); 44336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 44467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary oldContactsDictionary; 44578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka if (mSuggest != null) { 44678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = mSuggest.getContactsDictionary(); 44778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.close(); 44878ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } else { 44978ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = null; 45078ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 4516a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSuggest = new Suggest(this, subtypeLocale); 452297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.mAutoCorrectEnabled) { 453297e6d590bd957577c335aa8713a786145a70288Jean Chalard mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); 45478ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 455e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 4566a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 4576a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka 45867fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary = new UserBinaryDictionary(this, localeStr); 45967fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); 46078ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserDictionary(mUserDictionary); 461e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 46278ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka resetContactsDictionary(oldContactsDictionary); 463e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 4644f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 4654f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 4664f96bb4520de3610ae94da96b98e507ca7b76362satok if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 467a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka mUserHistoryDictionary = UserHistoryDictionary.getInstance( 468fd53b8cc2b78acd7e33f4dc39cfc2faaea92f0f8satok this, localeStr, Suggest.DIC_USER_HISTORY, mPrefs); 46978ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); 470923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 47136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 47214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard /** 47314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * Resets the contacts dictionary in mSuggest according to the user settings. 47414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 4752e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * This method takes an optional contacts dictionary to use when the locale hasn't changed 4762e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * since the contacts dictionary can be opened or closed as necessary depending on the settings. 47714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 47814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * @param oldContactsDictionary an optional dictionary to use, or null 47914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard */ 48067fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { 481297e6d590bd957577c335aa8713a786145a70288Jean Chalard final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict); 48214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 48367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary dictionaryToUse; 48414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (!shouldSetDictionary) { 48514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the dictionary is closed. If it is already closed, this is a no-op, 48614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // so it's safe to call it anyways. 48714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != oldContactsDictionary) oldContactsDictionary.close(); 48814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = null; 48914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 4902e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 4912e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang if (null != oldContactsDictionary) { 49267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard if (!oldContactsDictionary.mLocale.equals(locale)) { 49367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // If the locale has changed then recreate the contacts dictionary. This 49467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // allows locale dependent rules for handling bigram name predictions. 49567fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.close(); 49667fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard dictionaryToUse = new ContactsBinaryDictionary( 49767fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard this, Suggest.DIC_CONTACTS, locale); 4982e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } else { 49967fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // Make sure the old contacts dictionary is opened. If it is already open, 50067fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // this is a no-op, so it's safe to call it anyways. 50167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.reopen(this); 5022e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang dictionaryToUse = oldContactsDictionary; 5032e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } 50418222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } else { 50567fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, Suggest.DIC_CONTACTS, locale); 50618222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } 50714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 50814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 50914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != mSuggest) { 51014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard mSuggest.setContactsDictionary(dictionaryToUse); 51114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 512699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard } 513699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard 514cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /* package private */ void resetSuggestMainDict() { 5156a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 5166a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSuggest.resetMainDict(this, subtypeLocale); 5176a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 518cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard } 519cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 520466741d8a78965b8509bf527344f289e50873092Mike LeBeau @Override 521466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onDestroy() { 522e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa if (mSuggest != null) { 523e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.close(); 524e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest = null; 525979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project unregisterReceiver(mReceiver); 527cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard unregisterReceiver(mDictionaryPackInstallReceiver); 528979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 529979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.onDestroy(); 530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onDestroy(); 531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 533923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onConfigurationChanged(Configuration conf) { 535dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka mSubtypeSwitcher.onConfigurationChanged(conf); 536b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani // If orientation changed while predicting, commit the change 537f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka if (mDisplayOrientation != conf.orientation) { 538f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = conf.orientation; 539f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mHandler.startOrientationChanging(); 5405475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.beginBatchEdit(getCurrentInputConnection()); 5415475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 5425475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.finishComposingText(); 5435475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 5442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka if (isShowingOptionDialog()) 5452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka mOptionsDialog.dismiss(); 546b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 547923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onConfigurationChanged(conf); 548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 549b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public View onCreateInputView() { 5526c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka return mKeyboardSwitcher.onCreateInputView(); 5536c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka } 5546c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka 5556c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka @Override 5566c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka public void setInputView(View view) { 5576c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka super.setInputView(view); 558d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka mExtractArea = getWindow().getWindow().getDecorView() 559d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka .findViewById(android.R.id.extractArea); 560abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); 561913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer = view.findViewById(R.id.suggestions_container); 562913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view); 563913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) 564913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.setListener(this, view); 565f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka if (LatinImeLogger.sVISUALDEBUG) { 566f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); 567f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka } 568923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 570923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 571c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public void setCandidatesView(View view) { 572c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka // To ensure that CandidatesView will never be set. 573c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return; 574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 576a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker @Override 577e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 578e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInput(editorInfo, restarting); 57959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 58059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 58159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 582e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 583e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInputView(editorInfo, restarting); 58459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 58559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 58659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 58759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 58859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInputView(finishingInput); 58959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 59038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 59159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 59259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 59359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInput(); 59459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 59559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 5969cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka @Override 5979cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { 5984f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 5994f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 6006a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSubtypeSwitcher.updateSubtype(subtype); 6019cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka } 6029cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka 603e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) { 604e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInput(editorInfo, restarting); 60559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 60659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 6071cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka @SuppressWarnings("deprecation") 608e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { 609e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInputView(editorInfo, restarting); 61045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 611c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka LatinKeyboardView inputView = switcher.getKeyboardView(); 6128e09172df1bb176cc899940862c56bed9b9aec4esatok 613ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (editorInfo == null) { 614ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.e(TAG, "Null EditorInfo in onStartInputView()"); 615ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (LatinImeLogger.sDBG) { 616ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok throw new NullPointerException("Null EditorInfo in onStartInputView()"); 617ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 618ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok return; 619ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 62089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (DEBUG) { 621ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.d(TAG, "onStartInputView: editorInfo:" 622ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok + String.format("inputType=0x%08x imeOptions=0x%08x", 623ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok editorInfo.inputType, editorInfo.imeOptions)); 624b6fb5eb391987f3e426649a892cdcbf781957f5asatok Log.d(TAG, "All caps = " 625b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) 626b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", sentence caps = " 627b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0) 628b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", word caps = " 629b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); 630910b73127fa207dd26ec8124000262523b0aac0csatok } 6319bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 63207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge ResearchLogger.getInstance().start(); 63348a7681e064ae259b840f0e757da2d716043d893Kurt Partridge ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs); 6349bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 6351cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { 6364f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6374f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6381cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); 6394f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6401cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { 6414f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6424f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6434f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); 6444f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6454f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka 6461b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard mTargetApplicationInfo = 6471b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard TargetApplicationGetter.getCachedApplicationInfo(editorInfo.packageName); 6481b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard if (null == mTargetApplicationInfo) { 6491b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard new TargetApplicationGetter(this /* context */, this /* listener */) 6501b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard .execute(editorInfo.packageName); 6511b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard } 652b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 6537ef235f53f2291f22ddf8c56be9860a218b25bbbTadashi G. Takaoka LatinImeLogger.onStartInputView(editorInfo); 654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In landscape mode, this method gets called without the input view being created. 655979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (inputView == null) { 656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 659b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette // Forward this event to the accessibility utilities, if enabled. 660b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); 661b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette if (accessUtils.isTouchExplorationEnabled()) { 662e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka accessUtils.onStartInputViewInternal(editorInfo, restarting); 663b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette } 664b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette 6658d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka mSubtypeSwitcher.updateParametersOnStartInputView(); 6664ab730dbd34fad323063f2ffd31ce33de746668dsatok 667b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // The EditorInfo might have a flag that affects fullscreen mode. 668b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // Note: This call should be done by InputMethodService? 669b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka updateFullscreenMode(); 6701fead1d5f12928f90c723b5f7b88490cc7cd2a67Jean Chalard mLastSelectionStart = editorInfo.initialSelStart; 6711fead1d5f12928f90c723b5f7b88490cc7cd2a67Jean Chalard mLastSelectionEnd = editorInfo.initialSelEnd; 67280b66bb166f7f45adfcadcb84788477df9930828Jean Chalard mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode()); 673ccc35f7fa74860a8d737a4e9ff01fc0168dd329dJean Chalard mApplicationSpecifiedCompletions = null; 674c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 675c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.closing(); 676c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mEnteredText = null; 6772692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 678c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mDeleteCount = 0; 679120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 680c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 68117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 68217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 683297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mSuggest != null && mCurrentSettings.mAutoCorrectEnabled) { 684297e6d590bd957577c335aa8713a786145a70288Jean Chalard mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); 685549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka } 68617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 687297e6d590bd957577c335aa8713a786145a70288Jean Chalard switcher.loadKeyboard(editorInfo, mCurrentSettings); 688c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 689913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) 690913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.clear(); 691913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShownInternal( 692913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka isSuggestionsStripVisible(), /* needsInputViewShown */ false); 693c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka // Delay updating suggestions because keyboard input view may not be shown at this point. 694c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mHandler.postUpdateSuggestions(); 695ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 696c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 697297e6d590bd957577c335aa8713a786145a70288Jean Chalard inputView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn, 698297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.mKeyPreviewPopupDismissDelay); 699c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.setProximityCorrectionEnabled(true); 700c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 701c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); 702c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 703c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 7047214617622fce8f3fea6620e782c16336260a2a3Jean Chalard @Override 705b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard public void onTargetApplicationKnown(final ApplicationInfo info) { 706b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard mTargetApplicationInfo = info; 707b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard } 708b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 710e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka public void onWindowHidden() { 711d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 712d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.latinIME_onWindowHidden(mLastSelectionStart, mLastSelectionEnd, 713d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge getCurrentInputConnection()); 714d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 715e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka super.onWindowHidden(); 716f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 717e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka if (inputView != null) inputView.closing(); 718e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 719e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 72059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputInternal() { 721923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onFinishInput(); 722a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 723979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 72407cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 72507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge ResearchLogger.getInstance().stop(); 72607cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge } 727979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 728f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 729d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa if (inputView != null) inputView.closing(); 730466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 731466741d8a78965b8509bf527344f289e50873092Mike LeBeau 73259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputViewInternal(boolean finishingInput) { 7336495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa super.onFinishInputView(finishingInput); 734055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardSwitcher.onFinishInputView(); 735f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 7365f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (inputView != null) inputView.cancelAllMessages(); 737d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka // Remove pending messages related to update suggestions 738d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.cancelUpdateSuggestions(); 7396495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa } 7406495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa 7416495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa @Override 742923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onUpdateSelection(int oldSelStart, int oldSelEnd, 743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int newSelStart, int newSelEnd, 744104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard int composingSpanStart, int composingSpanEnd) { 745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, 746104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard composingSpanStart, composingSpanEnd); 747466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (DEBUG) { 748466741d8a78965b8509bf527344f289e50873092Mike LeBeau Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart 749466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ose=" + oldSelEnd 750025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lss=" + mLastSelectionStart 751025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lse=" + mLastSelectionEnd 752466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nss=" + newSelStart 753466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nse=" + newSelEnd 754104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", cs=" + composingSpanStart 755104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", ce=" + composingSpanEnd); 756466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 7579bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 758d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge final boolean expectingUpdateSelectionFromLogger = 759d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.getAndClearLatinIMEExpectingUpdateSelection(); 7609bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, 7619bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, 762d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge composingSpanEnd, mExpectingUpdateSelection, 76302308bec632a5df23325c916bffec5def16b22b4Jean Chalard expectingUpdateSelectionFromLogger, mConnection); 764d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (expectingUpdateSelectionFromLogger) { 765d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge return; 766d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 7679bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 768466741d8a78965b8509bf527344f289e50873092Mike LeBeau 769104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // TODO: refactor the following code to be less contrived. 770104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means 771104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // that the cursor is not at the end of the composing span, or there is a selection. 772104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place 773104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // as last time we were called (if there is a selection, it means the start hasn't 774104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // changed, so it's the end that did). 775104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean selectionChanged = (newSelStart != composingSpanEnd 776104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart; 777104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // if composingSpanStart and composingSpanEnd are -1, it means there is no composing 778104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // span in the view - we can use that to narrow down whether the cursor was moved 779104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // by us or not. If we are composing a word but there is no composing span, then 780104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // we know for sure the cursor moved while we were composing and we should reset 781104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // the state. 782104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1; 7834733609947c0ec74e460bd714fffca0518ade93aJean Chalard if (!mExpectingUpdateSelection) { 784cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // TAKE CARE: there is a race condition when we enter this test even when the user 785cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // did not explicitly move the cursor. This happens when typing fast, where two keys 786cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // turn this flag on in succession and both onUpdateSelection() calls arrive after 787cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // the second one - the first call successfully avoids this test, but the second one 788104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // enters. For the moment we rely on noComposingSpan to further reduce the impact. 78951fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 7909a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // TODO: the following is probably better done in resetEntireInputState(). 7919a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // it should only happen when the cursor moved, and the very purpose of the 7929a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // test below is to narrow down whether this happened or not. Likewise with 7939a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // the call to postUpdateShiftState. 79451fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // We set this to NONE because after a cursor move, we don't want the space 79551fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // state-related special processing to kick in. 79651fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard mSpaceState = SPACE_STATE_NONE; 79751fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 7988a3d369840d6061692a19ceb1eb7267a50a9e056Jean Chalard if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) { 7992649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetEntireInputState(); 8004c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 801beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 802beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 8034733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 8044733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = false; 8056b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not 8066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // here. It would probably be too expensive to call directly here but we may want to post a 8076b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // message to delay it. The point would be to unify behavior between backspace to the 8086b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // end of a word and manually put the pointer at the end of the word. 809466741d8a78965b8509bf527344f289e50873092Mike LeBeau 810979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Make a note of the cursor position 811979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionStart = newSelStart; 812979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionEnd = newSelEnd; 8137a8dac55278cedd838be325f56b4c52d973c61f5satok } 8147a8dac55278cedd838be325f56b4c52d973c61f5satok 815c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 816c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has clicked on the extracted text view, 817c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * when running in fullscreen mode. The default implementation hides 818913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * the suggestions view when this happens, but only if the extracted text 819c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * editor has a vertical scroll bar because its text doesn't fit. 820c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 821913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 822c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 823c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 824c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedTextClicked() { 825fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard if (isSuggestionsRequested()) return; 826c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 827c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedTextClicked(); 828c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 829c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 830c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 831c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has performed a cursor movement in the 832c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * extracted text view, when it is running in fullscreen mode. The default 833913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * implementation hides the suggestions view when a vertical movement 834c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * happens, but only if the extracted text editor has a vertical scroll bar 835c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * because its text doesn't fit. 836c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 837913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 838c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 839c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 840c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedCursorMovement(int dx, int dy) { 841fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard if (isSuggestionsRequested()) return; 842c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 843c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedCursorMovement(dx, dy); 844c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 845c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void hideWindow() { 848979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 849c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mKeyboardSwitcher.onHideWindow(); 850979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (TRACE) Debug.stopMethodTracing(); 8526e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani if (mOptionsDialog != null && mOptionsDialog.isShowing()) { 8536e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog.dismiss(); 8546e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog = null; 8556e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.hideWindow(); 857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 8601b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) { 861979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG) { 862a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa Log.i(TAG, "Received completions:"); 863bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok if (applicationSpecifiedCompletions != null) { 864bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 865bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); 866bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok } 867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 8699bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 8709bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); 8719bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 872dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn) { 8731b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; 8741b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka if (applicationSpecifiedCompletions == null) { 875b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani clearSuggestions(); 876923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 878a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 879660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = 88088bf1ba5263f5a5c1df367ddc401db4109ef8677Jean Chalard SuggestedWords.getFromApplicationSpecifiedCompletions( 8811dfef0336d5968dbd00b73489778cee1fb233d56Jean Chalard applicationSpecifiedCompletions); 882bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard final SuggestedWords suggestedWords = new SuggestedWords( 8837d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard applicationSuggestedWords, 8842e2519ee914d4bf9462950553840557a4c19faedJean Chalard false /* typedWordValid */, 885bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard false /* hasAutoCorrectionCandidate */, 886b5eeb724fc98bb7169683539027d9ba54ffb8b14Jean Chalard false /* allowsToBeAutoCorrected */, 88703a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isPunctuationSuggestions */, 8880142b997bf18f5d07e83b3fd403f0b3ea4736040satok false /* isObsoleteSuggestions */, 8890142b997bf18f5d07e83b3fd403f0b3ea4736040satok false /* isPrediction */); 890979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // When in fullscreen mode, show completions generated by the application 8914e112d07821d34c1dedd21b086817be9fce2fd47Jean Chalard final boolean isAutoCorrection = false; 8927d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard setSuggestions(suggestedWords, isAutoCorrection); 893dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 894b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard // TODO: is this the right thing to do? What should we auto-correct to in 895b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard // this case? This says to keep whatever the user typed. 896b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 897c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShown(true); 898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 900923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 901c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { 902913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // TODO: Modify this if we support suggestions with hard keyboard 903913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { 904433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 905433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final boolean inputViewShown = (keyboardView != null) ? keyboardView.isShown() : false; 906913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean shouldShowSuggestions = shown 907433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka && (needsInputViewShown ? inputViewShown : true); 9084b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka if (isFullscreenMode()) { 909913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 910913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.GONE); 9117a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } else { 912913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 913913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); 9147a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } 915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 916923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 917a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 918c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShown(boolean shown) { 919c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); 920543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa } 921543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa 922bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka private int getAdjustedBackingViewHeight() { 923bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka final int currentHeight = mKeyPreviewBackingView.getHeight(); 924bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka if (currentHeight > 0) { 925bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return currentHeight; 926c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 927c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 928c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final KeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 929bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka if (keyboardView == null) { 930bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return 0; 931bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka } 932c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int keyboardHeight = keyboardView.getHeight(); 933c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int suggestionsHeight = mSuggestionsContainer.getHeight(); 934c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int displayHeight = mResources.getDisplayMetrics().heightPixels; 935c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final Rect rect = new Rect(); 936c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); 937c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int notificationBarHeight = rect.top; 938c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight 939c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka - keyboardHeight; 940c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 941c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final LayoutParams params = mKeyPreviewBackingView.getLayoutParams(); 942c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka params.height = mSuggestionsView.setMoreSuggestionsHeight(remainingHeight); 943c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.setLayoutParams(params); 944bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return params.height; 945c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 946c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 947543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa @Override 948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onComputeInsets(InputMethodService.Insets outInsets) { 949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onComputeInsets(outInsets); 950f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 951913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (inputView == null || mSuggestionsContainer == null) 95246ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka return; 953b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int adjustedBackingHeight = getAdjustedBackingViewHeight(); 954b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); 955b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int backingHeight = backingGone ? 0 : adjustedBackingHeight; 956d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // In fullscreen mode, the height of the extract area managed by InputMethodService should 957d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // be considered. 958d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. 959d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0; 96059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0 96159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka : mSuggestionsContainer.getHeight(); 962d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extraHeight = extractHeight + backingHeight + suggestionsHeight; 963abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka int touchY = extraHeight; 9649e347d3d448e48229c46aad394ec9bd60cd5807bsatok // Need to set touchable region only if input view is being shown 965433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 966433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka if (keyboardView != null && keyboardView.isShown()) { 967913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { 96859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka touchY -= suggestionsHeight; 9699e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 9707a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka final int touchWidth = inputView.getWidth(); 971abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka final int touchHeight = inputView.getHeight() + extraHeight 9727a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka // Extend touchable region below the keyboard. 9737a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + EXTENDED_TOUCHABLE_REGION_HEIGHT; 97413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; 97513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight); 9769e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 97746ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.contentTopInsets = touchY; 97846ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.visibleTopInsets = touchY; 979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 980a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 982979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean onEvaluateFullscreenMode() { 9839751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka // Reread resource value here, because this method is called by framework anytime as needed. 9849751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka final boolean isFullscreenModeAllowed = 985297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.isFullscreenModeAllowed(getResources()); 9869751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka return super.onEvaluateFullscreenMode() && isFullscreenModeAllowed; 98759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka } 98859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka 98959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka @Override 99059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka public void updateFullscreenMode() { 99159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka super.updateFullscreenMode(); 992f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka 99359010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka if (mKeyPreviewBackingView == null) return; 994549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka // In fullscreen mode, no need to have extra space to show the key preview. 99559010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka // If not, we should have extra space above the keyboard to show the key preview. 996549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); 997979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 998979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 9992649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // This will reset the whole input state to the starting state. It will clear 10002649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // the composing word, reset the last composed word, tell the inputconnection 10012649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // and the composingStateManager about it. 10022649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard private void resetEntireInputState() { 10032649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 10042649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard updateSuggestions(); 10055475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.finishComposingText(); 10062649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard } 10072649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard 10082692a8700737d8eed268039aa27b22a31669da08Jean Chalard private void resetComposingState(final boolean alsoResetLastComposedWord) { 10092692a8700737d8eed268039aa27b22a31669da08Jean Chalard mWordComposer.reset(); 10102692a8700737d8eed268039aa27b22a31669da08Jean Chalard if (alsoResetLastComposedWord) 10112692a8700737d8eed268039aa27b22a31669da08Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 10122692a8700737d8eed268039aa27b22a31669da08Jean Chalard } 10132692a8700737d8eed268039aa27b22a31669da08Jean Chalard 10145475b38328171a0841ae18074bd45380ec567e90Jean Chalard public void commitTyped(final int separatorCode) { 1015196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) return; 10163651220327c051d8017045aa5e8919461507b3f8Jean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 10173651220327c051d8017045aa5e8919461507b3f8Jean Chalard if (typedWord.length() > 0) { 10185475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(typedWord, 1); 10195475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 10205475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_commitText(typedWord); 1021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1022c54d558e2e70bdfb2c1078cae7b88440d421dc67satok final CharSequence prevWord = addToUserHistoryDictionary(typedWord); 1023c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mLastComposedWord = mWordComposer.commitWord( 1024c54d558e2e70bdfb2c1078cae7b88440d421dc67satok LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), 1025c54d558e2e70bdfb2c1078cae7b88440d421dc67satok separatorCode, prevWord); 1026923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 10278558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa updateSuggestions(); 1028923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1029923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1030553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka public int getCurrentAutoCapsState() { 1031297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; 103203ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 103303ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final EditorInfo ei = getCurrentInputEditorInfo(); 1034553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; 103503ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 103603ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final int inputType = ei.inputType; 1037553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) { 1038553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka return TextUtils.CAP_MODE_CHARACTERS; 1039553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka } 104003ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 104103ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final boolean noNeedToCheckCapsMode = (inputType & (InputType.TYPE_TEXT_FLAG_CAP_SENTENCES 104203ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka | InputType.TYPE_TEXT_FLAG_CAP_WORDS)) == 0; 1043553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if (noNeedToCheckCapsMode) return Constants.TextUtils.CAP_MODE_OFF; 104403ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 104516950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka // Avoid making heavy round-trip IPC calls of {@link InputConnection#getCursorCapsMode} 104616950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka // unless needed. 104716950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka if (mWordComposer.isComposingWord()) return Constants.TextUtils.CAP_MODE_OFF; 104816950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka 104903ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // TODO: This blocking IPC call is heavy. Consider doing this without using IPC calls. 105003ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // Note: getCursorCapsMode() returns the current capitalization mode that is any 105103ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none 105203ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // of them. 10535475b38328171a0841ae18074bd45380ec567e90Jean Chalard return mConnection.getCursorCapsMode(inputType); 10541c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 10551c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1056bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard private void swapSwapperAndSpace() { 10575475b38328171a0841ae18074bd45380ec567e90Jean Chalard CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); 1058863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. 1059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastTwo != null && lastTwo.length() == 2 1060863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard && lastTwo.charAt(0) == Keyboard.CODE_SPACE) { 10615475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 1062d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1063d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(2); 1064d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 10655475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(lastTwo.charAt(1) + " ", 1); 1066d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1067d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_swapSwapperAndSpaceWhileInBatchEdit(); 1068d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1069b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 10704ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 10714ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 10724ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1073bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard private boolean maybeDoubleSpace() { 1074297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.mCorrectionMode == Suggest.CORRECTION_NONE) return false; 10755475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0); 1076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastThree != null && lastThree.length() == 3 1077344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka && canBeFollowedByPeriod(lastThree.charAt(0)) 1078571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastThree.charAt(1) == Keyboard.CODE_SPACE 1079fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka && lastThree.charAt(2) == Keyboard.CODE_SPACE 1080fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka && mHandler.isAcceptingDoubleSpaces()) { 1081fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka mHandler.cancelDoubleSpacesTimer(); 10825475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 10835475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(". ", 1); 1084d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1085d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_doubleSpaceAutoPeriod(); 1086d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1087b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1088120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 1089923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1090120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return false; 1091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1092a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1093344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka private static boolean canBeFollowedByPeriod(final int codePoint) { 1094344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: Check again whether there really ain't a better way to check this. 1095344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: This should probably be language-dependant... 1096344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka return Character.isLetterOrDigit(codePoint) 1097344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_SINGLE_QUOTE 1098344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_DOUBLE_QUOTE 1099344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS 1100344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET 1101344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET 1102344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; 1103344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka } 1104344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka 1105c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 1106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean addWordToDictionary(String word) { 110767fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary.addWordToUserDictionary(word, 128); 11086558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // Suggestion strip should be updated after the operation of adding word to the 11096558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // user dictionary 1110d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 11148fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean isAlphabet(int code) { 11158fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka return Character.isLetter(code); 1116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1117a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1118e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka private void onSettingsKeyPressed() { 1119cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return; 1120911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa showSubtypeSelectorAndSettings(); 11219a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11229a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1123cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa // Virtual codes representing custom requests. These are used in onCustomRequest() below. 1124cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; 1125cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa 1126cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa @Override 1127cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public boolean onCustomRequest(int requestCode) { 1128cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return false; 1129cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa switch (requestCode) { 1130cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa case CODE_SHOW_INPUT_METHOD_PICKER: 113155d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka if (ImfUtils.hasMultipleEnabledIMEsOrSubtypes( 113255d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka this, true /* include aux subtypes */)) { 113379efbed76f638be298493107fa2d0cd1b5eb529esatok mImm.showInputMethodPicker(); 1134cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return true; 11359a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1136cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 11379a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1138cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 11399a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11409a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 11419a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok private boolean isShowingOptionDialog() { 11429a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok return mOptionsDialog != null && mOptionsDialog.isShowing(); 11439a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11449a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 114505bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka private static int getActionId(Keyboard keyboard) { 114605bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE; 11477a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11487a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11498f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka private void performEditorAction(int actionId) { 11505475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.performEditorAction(actionId); 11515475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 11525475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_performEditorAction(actionId); 11537a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11547a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11557a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 115681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private void handleLanguageSwitchKey() { 1157297e6d590bd957577c335aa8713a786145a70288Jean Chalard final boolean includesOtherImes = mCurrentSettings.mIncludesOtherImesInLanguageSwitchList; 115881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final IBinder token = getWindow().getWindow().getAttributes().token; 115981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if (mShouldSwitchToLastSubtype) { 11609cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka final InputMethodSubtype lastSubtype = mImm.getLastInputMethodSubtype(); 1161ae2388c7f799ab565f63d3ba83abaf3300475fd0Tadashi G. Takaoka final boolean lastSubtypeBelongsToThisIme = 1162ae2388c7f799ab565f63d3ba83abaf3300475fd0Tadashi G. Takaoka ImfUtils.checkIfSubtypeBelongsToThisImeAndEnabled(this, lastSubtype); 116381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if ((includesOtherImes || lastSubtypeBelongsToThisIme) 116481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && mImm.switchToLastInputMethod(token)) { 116581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = false; 116681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else { 116781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mImm.switchToNextInputMethod(token, !includesOtherImes); 116881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 116981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 117081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else { 117181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mImm.switchToNextInputMethod(token, !includesOtherImes); 117281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 117381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 117481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka 11755475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void sendUpDownEnterOrBackspace(final int code) { 11764e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard final long eventTime = SystemClock.uptimeMillis(); 11775475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, 11784e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_DOWN, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 11794e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 11805475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, 11814e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_UP, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 11824e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 11834e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 11844e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard 11857a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void sendKeyCodePoint(int code) { 11867a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // TODO: Remove this special handling of digit letters. 11877a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. 11887a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (code >= '0' && code <= '9') { 11897a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka super.sendKeyChar((char)code); 11907a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return; 11917a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11927a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11935475b38328171a0841ae18074bd45380ec567e90Jean Chalard // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because 11945475b38328171a0841ae18074bd45380ec567e90Jean Chalard // we want to be able to compile against the Ice Cream Sandwich SDK. 11955475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (Keyboard.CODE_ENTER == code && mTargetApplicationInfo != null 11965475b38328171a0841ae18074bd45380ec567e90Jean Chalard && mTargetApplicationInfo.targetSdkVersion < 16) { 11975475b38328171a0841ae18074bd45380ec567e90Jean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 11985475b38328171a0841ae18074bd45380ec567e90Jean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 11995475b38328171a0841ae18074bd45380ec567e90Jean Chalard // reasons (there are race conditions with commits) but some applications are 12005475b38328171a0841ae18074bd45380ec567e90Jean Chalard // relying on this behavior so we continue to support it for older apps. 12015475b38328171a0841ae18074bd45380ec567e90Jean Chalard sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_ENTER); 12025475b38328171a0841ae18074bd45380ec567e90Jean Chalard } else { 12035475b38328171a0841ae18074bd45380ec567e90Jean Chalard final String text = new String(new int[] { code }, 0, 1); 12045475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, text.length()); 12055475b38328171a0841ae18074bd45380ec567e90Jean Chalard } 12065475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 12075475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_sendKeyCodePoint(code); 12087a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 12115f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Implementation of {@link KeyboardActionListener}. 12125a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1213ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok public void onCodeInput(int primaryCode, int x, int y) { 1214175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final long when = SystemClock.uptimeMillis(); 1215571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { 1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDeleteCount = 0; 1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mLastKeyTime = when; 1219e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard mConnection.beginBatchEdit(getCurrentInputConnection()); 1220fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge 1221c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 122207cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); 1223fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge } 1224fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge 1225175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1226120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // The space state depends only on the last character pressed and its own previous 1227120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // state. Here, we revert the space state to neutral if the key is actually modifying 1228120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // the input contents (any non-shift key), which is what we should do for 1229120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // all inputs that do not result in a special state. Each character handling is then 1230120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // free to override the state as they see fit. 1231120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState = mSpaceState; 123270852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false; 1233ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1234ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa // TODO: Consolidate the double space timer, mLastKeyTime, and the space state. 1235ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa if (primaryCode != Keyboard.CODE_SPACE) { 1236ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 1237ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa } 1238ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1239c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 1241571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_DELETE: 1242120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1243120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleBackspace(spaceState); 12444189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka mDeleteCount++; 12454733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 124681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 1247140467b8b65eb9087a9b7f744dbb8a30481effe7Kurt Partridge LatinImeLogger.logOnDelete(x, y); 12484189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1249571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_SHIFT: 1250e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 12512a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka // Shift and symbol key is handled in onPressKey() and onReleaseKey(). 12524189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1253e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SETTINGS: 125493246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka onSettingsKeyPressed(); 12554189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1256d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka case Keyboard.CODE_SHORTCUT: 125793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka mSubtypeSwitcher.switchToShortcutIME(); 12584189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 12597a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka case Keyboard.CODE_ACTION_ENTER: 12608f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(getActionId(switcher.getKeyboard())); 12617a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka break; 126205bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case Keyboard.CODE_ACTION_NEXT: 12638f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_NEXT); 126405bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka break; 126505bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case Keyboard.CODE_ACTION_PREVIOUS: 12668f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); 12674189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 126881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka case Keyboard.CODE_LANGUAGE_SWITCH: 126981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka handleLanguageSwitchKey(); 127081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka break; 1271724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge case Keyboard.CODE_RESEARCH: 1272724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1273724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge ResearchLogger.getInstance().presentResearchDialog(this); 1274724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge } 1275724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge break; 12764189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka default: 12770b831ba2aaf7baf7be402f2245b225a04c28fadaTadashi G. Takaoka if (primaryCode == Keyboard.CODE_TAB 12780b831ba2aaf7baf7be402f2245b225a04c28fadaTadashi G. Takaoka && mInputAttributes.mEditorAction == EditorInfo.IME_ACTION_NEXT) { 12790b831ba2aaf7baf7be402f2245b225a04c28fadaTadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_NEXT); 12800b831ba2aaf7baf7be402f2245b225a04c28fadaTadashi G. Takaoka break; 12810b831ba2aaf7baf7be402f2245b225a04c28fadaTadashi G. Takaoka } 1282120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1283297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWordSeparator(primaryCode)) { 1284c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); 12854189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 12868dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 12878dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { 12888dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka handleCharacter(primaryCode, x, y, spaceState); 12898dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } else { 12908dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka handleCharacter(primaryCode, NOT_A_TOUCH_COORDINATE, NOT_A_TOUCH_COORDINATE, 12918dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka spaceState); 12928dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } 12934189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 12944733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 129581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 12964733609947c0ec74e460bd714fffca0518ade93aJean Chalard break; 1297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1298eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka switcher.onCodeInput(primaryCode); 1299125de3dfdf548359de890247907f2e6f430008ecJean Chalard // Reset after any single keystroke, except shift and symbol-shift 1300125de3dfdf548359de890247907f2e6f430008ecJean Chalard if (!didAutoCorrect && primaryCode != Keyboard.CODE_SHIFT 1301125de3dfdf548359de890247907f2e6f430008ecJean Chalard && primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL) 1302c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard mLastComposedWord.deactivate(); 1303dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = null; 1304e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard mConnection.endBatchEdit(); 1305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1306a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 13075a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13088aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onTextInput(CharSequence text) { 13095475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.beginBatchEdit(getCurrentInputConnection()); 13105475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 13115475b38328171a0841ae18074bd45380ec567e90Jean Chalard text = specificTldProcessingOnTextInput(text); 1312fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == mSpaceState) { 13137a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 1314fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 13155475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, 1); 1316d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1317d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_commitText(text); 1318d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 13195475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 1320b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 13218cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); 1322120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1323dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = text; 13242692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 1325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 13275475b38328171a0841ae18074bd45380ec567e90Jean Chalard private CharSequence specificTldProcessingOnTextInput(final CharSequence text) { 1328fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (text.length() <= 1 || text.charAt(0) != Keyboard.CODE_PERIOD 1329fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard || !Character.isLetter(text.charAt(1))) { 1330fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Not a tld: do nothing. 1331fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1332fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 133312d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // We have a TLD (or something that looks like this): make sure we don't add 133412d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // a space even if currently in phantom mode. 133512d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard mSpaceState = SPACE_STATE_NONE; 13365475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0); 1337fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (lastOne != null && lastOne.length() == 1 1338fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard && lastOne.charAt(0) == Keyboard.CODE_PERIOD) { 1339fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text.subSequence(1, text.length()); 1340fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else { 1341fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1342fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1343fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1344fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 13455a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13468aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() { 134783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka // User released a finger outside any key 13485f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka mKeyboardSwitcher.onCancelInput(); 134983e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } 135083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka 1351120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleBackspace(final int spaceState) { 13522245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard // In many cases, we may have to put the keyboard in auto-shift state again. 1353beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 13542245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard 1355747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) { 13565c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // Cancel multi-character input: remove the text we just entered. 13575c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // This is triggered on backspace after a key that inputs multiple characters, 13585c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // like the smiley key or the .com key. 1359d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int length = mEnteredText.length(); 13605475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(length, 0); 1361d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1362d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(length); 1363d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 13645c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. 13655c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // In addition we know that spaceState is false, and that we should not be 13665c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // reverting any autocorrect at this point. So we can safely return. 13675c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard return; 13685c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard } 13695c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard 1370196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 13713651220327c051d8017045aa5e8919461507b3f8Jean Chalard final int length = mWordComposer.size(); 1372923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (length > 0) { 13739318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.deleteLast(); 13745475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1375196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // If we have deleted the last remaining character of a word, then we are not 1376196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // isComposingWord() any more. 1377196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) { 1378196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // Not composing word any more, so we can show bigrams. 1379cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.postUpdateBigramPredictions(); 138089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1381196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // Still composing a word, so we still have letters to deduce a suggestion from. 138289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard mHandler.postUpdateSuggestions(); 138389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 1384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 13855475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1386d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1387d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(1); 1388d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1389923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1390890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } else { 13915935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard if (mLastComposedWord.canRevertCommit()) { 1392d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard Utils.Stats.onAutoCorrectionCancellation(); 13935475b38328171a0841ae18074bd45380ec567e90Jean Chalard revertCommit(); 1394120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return; 1395120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1396d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (SPACE_STATE_DOUBLE == spaceState) { 1397243e370fcb1c2cb8608614206075ecdbe79a6372Jean Chalard mHandler.cancelDoubleSpacesTimer(); 13985475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (revertDoubleSpaceWhileInBatchEdit()) { 1399d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // No need to reset mSpaceState, it has already be done (that's why we 1400d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // receive it as a parameter) 1401d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1402d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 1403d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 14045475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (revertSwapPunctuation()) { 1405d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // Likewise 1406d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1407d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 14084733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 1409504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka 14104fef31510df542a3324426a6750950194d016086Jean Chalard // No cancelling of commit/double space/swap: we have a regular backspace. 14114fef31510df542a3324426a6750950194d016086Jean Chalard // We should backspace one char and restart suggestion if at the end of a word. 14124fef31510df542a3324426a6750950194d016086Jean Chalard if (mLastSelectionStart != mLastSelectionEnd) { 14134fef31510df542a3324426a6750950194d016086Jean Chalard // If there is a selection, remove it. 14144fef31510df542a3324426a6750950194d016086Jean Chalard final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; 14155475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); 14165475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(lengthToDelete, 0); 1417d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1418d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(lengthToDelete); 1419d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 14206558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } else { 14214fef31510df542a3324426a6750950194d016086Jean Chalard // There is no selection, just delete one character. 14224fef31510df542a3324426a6750950194d016086Jean Chalard if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { 14234fef31510df542a3324426a6750950194d016086Jean Chalard // This should never happen. 14244fef31510df542a3324426a6750950194d016086Jean Chalard Log.e(TAG, "Backspace when we don't know the selection position"); 14256558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 14264e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because 14274e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // we want to be able to compile against the Ice Cream Sandwich SDK. 14284e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard if (mTargetApplicationInfo != null 14294e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard && mTargetApplicationInfo.targetSdkVersion < 16) { 14304e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 14314e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 14324e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // reasons (there are race conditions with commits) but some applications are 14334e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // relying on this behavior so we continue to support it for older apps. 14345475b38328171a0841ae18074bd45380ec567e90Jean Chalard sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_DEL); 14354e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } else { 14365475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 14374e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 1438d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1439d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(1); 1440d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 14414fef31510df542a3324426a6750950194d016086Jean Chalard if (mDeleteCount > DELETE_ACCELERATE_AT) { 14425475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1443d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1444d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(1); 1445d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1446edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 14484fef31510df542a3324426a6750950194d016086Jean Chalard if (isSuggestionsRequested()) { 14495475b38328171a0841ae18074bd45380ec567e90Jean Chalard restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); 14504fef31510df542a3324426a6750950194d016086Jean Chalard } 1451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1453923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1454e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard private boolean maybeStripSpace(final int code, 1455e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final int spaceState, final boolean isFromSuggestionStrip) { 1456e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1457bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1458e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1459e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else if ((SPACE_STATE_WEAK == spaceState 1460e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard || SPACE_STATE_SWAP_PUNCTUATION == spaceState) 1461e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard && isFromSuggestionStrip) { 1462297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWeakSpaceSwapper(code)) { 1463e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return true; 1464e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1465297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWeakSpaceStripper(code)) { 1466bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1467e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1468e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1469e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1470e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1471e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1472e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1473e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1474e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1475ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void handleCharacter(final int primaryCode, final int x, 1476120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int y, final int spaceState) { 1477196d82cdd740580ed79d801483dbc282be85d076Jean Chalard boolean isComposingWord = mWordComposer.isComposingWord(); 1478fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1479fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1480297e6d590bd957577c335aa8713a786145a70288Jean Chalard !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) { 1481fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (isComposingWord) { 1482fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Sanity check 1483fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard throw new RuntimeException("Should not be composing here"); 1484fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 14857a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 1486fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1487fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1488d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several 1489d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI 1490d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // thread here. 1491d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard if (!isComposingWord && (isAlphabet(primaryCode) 1492297e6d590bd957577c335aa8713a786145a70288Jean Chalard || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) 1493297e6d590bd957577c335aa8713a786145a70288Jean Chalard && isSuggestionsRequested() && 1494297e6d590bd957577c335aa8713a786145a70288Jean Chalard !mConnection.isCursorTouchingWord(mCurrentSettings)) { 1495736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Reset entirely the composing state anyway, then start composing a new word unless 1496736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // the character is a single quote. The idea here is, single quote is not a 1497736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // separator and it should be treated as a normal character, except in the first 1498736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // position where it should not start composing a word. 1499736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode); 1500736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Here we don't need to reset the last composed word. It will be reset 1501736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // when we commit this one, if we ever do; if on the other hand we backspace 1502736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // it entirely and resume suggestions on the previous word, we'd like to still 1503736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // have touch coordinates for it. 1504736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard resetComposingState(false /* alsoResetLastComposedWord */); 1505736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard clearSuggestions(); 1506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15077b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (isComposingWord) { 1508ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mWordComposer.add( 1509ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok primaryCode, x, y, mKeyboardSwitcher.getKeyboardView().getKeyDetector()); 15105475b38328171a0841ae18074bd45380ec567e90Jean Chalard // If it's the first letter, make note of auto-caps state 15115475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (mWordComposer.size() == 1) { 15125475b38328171a0841ae18074bd45380ec567e90Jean Chalard mWordComposer.setAutoCapitalized( 15135475b38328171a0841ae18074bd45380ec567e90Jean Chalard getCurrentAutoCapsState() != Constants.TextUtils.CAP_MODE_OFF); 1514923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15155475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1516d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1518e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, 1519e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); 1520863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 15217a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 1522e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1523e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (swapWeakSpace) { 1524bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 1525e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard mSpaceState = SPACE_STATE_WEAK; 1526e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 15275262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // Some characters are not word separators, yet they don't start a new 15285262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // composing span. For these, we haven't changed the suggestion strip, and 15295262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // if the "add to dictionary" hint is shown, we should do so now. Examples of 15305262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // such characters include single quote, dollar, and others; the exact list is 15315262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // the list of characters for which we enter handleCharacterWhileInBatchEdit 15325262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // that don't match the test if ((isAlphabet...)) at the top of this method. 15335262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard if (null != mSuggestionsView && mSuggestionsView.dismissAddToDictionaryHint()) { 15345262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard mHandler.postUpdateBigramPredictions(); 15355262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard } 1536e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1537e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard Utils.Stats.onNonSeparator((char)primaryCode, x, y); 1538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1540c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard // Returns true if we did an autocorrection, false otherwise. 1541c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard private boolean handleSeparator(final int primaryCode, final int x, final int y, 1542120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState) { 154355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa // Should dismiss the "Touch again to save" message when handling separator 1544913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { 1545cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.cancelUpdateBigramPredictions(); 1546d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 15476558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 15486558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 1549c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Handle separator 1551196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 1552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In certain languages where single quote is a separator, it's better 1553a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker // not to auto correct, but accept the typed word. For instance, 1554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // in Italian dov' should not be expanded to dove' because the elision 1555923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // requires the last vowel to be removed. 1556297e6d590bd957577c335aa8713a786145a70288Jean Chalard final boolean shouldAutoCorrect = mCurrentSettings.mAutoCorrectEnabled 1557dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && !mInputAttributes.mInputTypeNoAutoCorrect; 155817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { 15595475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitCurrentAutoCorrection(primaryCode); 1560c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = true; 1561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 15625475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(primaryCode); 1563923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1564923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15654ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1566e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, spaceState, 1567e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); 1568863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 156900ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1570297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { 157100ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard sendKeyCodePoint(Keyboard.CODE_SPACE); 157200ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard } 15737a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 157489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 157589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (Keyboard.CODE_SPACE == primaryCode) { 1576120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (isSuggestionsRequested()) { 1577bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard if (maybeDoubleSpace()) { 1578120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_DOUBLE; 1579120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else if (!isShowingPunctuationList()) { 1580120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_WEAK; 1581120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1582126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 1583120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1584120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mHandler.startDoubleSpacesTimer(); 1585297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mConnection.isCursorTouchingWord(mCurrentSettings)) { 158689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard mHandler.cancelUpdateSuggestions(); 1587cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.postUpdateBigramPredictions(); 158889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 158989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1590fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (swapWeakSpace) { 1591bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 15924721427c7de3600f6fe7dfff16508a6a974fb3e4Jean Chalard mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; 1593fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else if (SPACE_STATE_PHANTOM == spaceState) { 1594fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // If we are in phantom space state, and the user presses a separator, we want to 1595fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // stay in phantom space state so that the next keypress has a chance to add the 1596fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // space. For example, if I type "Good dat", pick "day" from the suggestion strip 1597fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // then insert a comma and go on to typing the next word, I want the space to be 1598fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // inserted automatically before the next word, the same way it is when I don't 1599fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // input the comma. 1600fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1601120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1602120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 160389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Set punctuation right away. onUpdateSelection will fire but tests whether it is 160489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // already displayed or not, so it's okay. 160555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka setPunctuationSuggestions(); 1606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1607120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1608406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)primaryCode, x, y); 1609120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1610c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard return didAutoCorrect; 1611923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1612466741d8a78965b8509bf527344f289e50873092Mike LeBeau 161377d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard private CharSequence getTextWithUnderline(final CharSequence text) { 16140a59ac2ba88ac1f99151d9336136bc6fe7d416c0Jean Chalard return mIsAutoCorrectionIndicatorOn 161577d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) 1616fda847a870829f1491cbd5325f9c985213081149Jean Chalard : text; 161777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 161877d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard 1619923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void handleClose() { 16205475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 1621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestHideSelf(0); 1622c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 16231679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka if (inputView != null) 16241679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka inputView.closing(); 1625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1626923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 16277a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isSuggestionsRequested() { 16284b9e6ee6fb408e2793e9ead5de2d6b45270d1f0dJean Chalard // TODO: move this method to mSettingsValues 1629dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard return mInputAttributes.mIsSettingsSuggestionStripOn 1630297e6d590bd957577c335aa8713a786145a70288Jean Chalard && (mCurrentSettings.mCorrectionMode > 0 || isShowingSuggestionsStrip()); 1631923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1632a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 16337a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isShowingPunctuationList() { 1634cb8cb95d0afd340de9f1a0e15948f0068d2450bcKen Wakasa if (mSuggestionsView == null) return false; 1635297e6d590bd957577c335aa8713a786145a70288Jean Chalard return mCurrentSettings.mSuggestPuncList == mSuggestionsView.getSuggestions(); 16367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16377599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 16387a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isShowingSuggestionsStrip() { 1639297e6d590bd957577c335aa8713a786145a70288Jean Chalard return mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation); 16407599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16417599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1642913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public boolean isSuggestionsStripVisible() { 1643913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView == null) 1644b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa return false; 1645d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard if (mSuggestionsView.isShowingAddToDictionaryHint()) 16469fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (!isShowingSuggestionsStrip()) 16489fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return false; 1649dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn) 16509fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16519fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return isSuggestionsRequested(); 1652923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1654409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void switchToKeyboardView() { 1655060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (DEBUG) { 1656060efb6d82af1f896d90cb845c8ae07c726f85e1satok Log.d(TAG, "Switch to keyboard view."); 1657060efb6d82af1f896d90cb845c8ae07c726f85e1satok } 16589bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 16599bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_switchToKeyboardView(); 16609bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 1661c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka View v = mKeyboardSwitcher.getKeyboardView(); 1662060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (v != null) { 1663060efb6d82af1f896d90cb845c8ae07c726f85e1satok // Confirms that the keyboard view doesn't have parent view. 1664060efb6d82af1f896d90cb845c8ae07c726f85e1satok ViewParent p = v.getParent(); 1665060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (p != null && p instanceof ViewGroup) { 1666060efb6d82af1f896d90cb845c8ae07c726f85e1satok ((ViewGroup) p).removeView(v); 16675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 1668060efb6d82af1f896d90cb845c8ae07c726f85e1satok setInputView(v); 1669060efb6d82af1f896d90cb845c8ae07c726f85e1satok } 1670913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1671060efb6d82af1f896d90cb845c8ae07c726f85e1satok updateInputViewShown(); 1672060efb6d82af1f896d90cb845c8ae07c726f85e1satok mHandler.postUpdateSuggestions(); 1673466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1674466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1675409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void clearSuggestions() { 1676dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setSuggestions(SuggestedWords.EMPTY, false); 16777204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1678466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1679466741d8a78965b8509bf527344f289e50873092Mike LeBeau 16802be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard private void setSuggestions(final SuggestedWords words, final boolean isAutoCorrection) { 1681913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) { 1682913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.setSuggestions(words); 1683dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection); 1684466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1685d02783cb63293507e8544ea60d07559092ce83d4Jean Chalard } 1686ec780e2868962bf17f0dfd35d36895f543bde40asatok 168738e535e59676ac4d7bf27026fe3e16fcd9eb292eJean Chalard private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { 1688ec780e2868962bf17f0dfd35d36895f543bde40asatok // Put a blue underline to a word in TextView which will be auto-corrected. 16892be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator 16902be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard && mWordComposer.isComposingWord()) { 16912be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; 16922be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard final CharSequence textWithUnderline = 16932be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard getTextWithUnderline(mWordComposer.getTypedWord()); 16945475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(textWithUnderline, 1); 1695ec780e2868962bf17f0dfd35d36895f543bde40asatok } 1696466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1697466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1698409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void updateSuggestions() { 1699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Check if we have a suggestion engine attached. 1700911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa if ((mSuggest == null || !isSuggestionsRequested())) { 1701edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard if (mWordComposer.isComposingWord()) { 1702edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard Log.w(TAG, "Called updateSuggestions but suggestions were not requested!"); 1703edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 1704edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1705923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1707466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1708cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard mHandler.cancelUpdateSuggestions(); 1709cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard mHandler.cancelUpdateBigramPredictions(); 1710cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard 1711196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) { 1712ca26f20fa4903de46e374babbfba8c8a1a5cac93satok setPunctuationSuggestions(); 1713923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1714923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1715979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 17169f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok // TODO: May need a better way of retrieving previous word 1717297e6d590bd957577c335aa8713a786145a70288Jean Chalard final CharSequence prevWord = mConnection.getPreviousWord(mCurrentSettings.mWordSeparators); 1718dc5dfe37e06eb1d550d7aa5156cff226334d4e1eJean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 17192be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard // getSuggestedWords handles gracefully a null value of prevWord 17205b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, 17214b9e6ee6fb408e2793e9ead5de2d6b45270d1f0dJean Chalard prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), 1722297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.mCorrectionMode); 1723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1724a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa // Basically, we update the suggestion strip only when suggestion count > 1. However, 1725a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa // there is an exception: We update the suggestion strip whenever typed word's length 1726f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // is 1 or typed word is found in dictionary, regardless of suggestion count. Actually, 1727f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // in most cases, suggestion count is 1 when typed word's length is 1, but we do always 1728f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // need to clear the previous state when the user starts typing a word (i.e. typed word's 1729f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // length == 1). 17305b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard if (suggestedWords.size() > 1 || typedWord.length() == 1 17315b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard || !suggestedWords.mAllowsToBeAutoCorrected 1732838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard || mSuggestionsView.isShowingAddToDictionaryHint()) { 17335b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard showSuggestions(suggestedWords, typedWord); 1734838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard } else { 1735838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard SuggestedWords previousSuggestions = mSuggestionsView.getSuggestions(); 1736297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (previousSuggestions == mCurrentSettings.mSuggestPuncList) { 1737838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard previousSuggestions = SuggestedWords.EMPTY; 1738fe1a6d961cf039357f061482461e4d2e951ad346satok } 17394ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = 174088bf1ba5263f5a5c1df367ddc401db4109ef8677Jean Chalard SuggestedWords.getTypedWordAndPreviousSuggestions( 17414ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard typedWord, previousSuggestions); 17427d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard final SuggestedWords obsoleteSuggestedWords = 1743bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard new SuggestedWords(typedWordAndPreviousSuggestions, 17442e2519ee914d4bf9462950553840557a4c19faedJean Chalard false /* typedWordValid */, 1745bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard false /* hasAutoCorrectionCandidate */, 1746b5eeb724fc98bb7169683539027d9ba54ffb8b14Jean Chalard false /* allowsToBeAutoCorrected */, 174703a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isPunctuationSuggestions */, 17480142b997bf18f5d07e83b3fd403f0b3ea4736040satok true /* isObsoleteSuggestions */, 17490142b997bf18f5d07e83b3fd403f0b3ea4736040satok false /* isPrediction */); 17507d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard showSuggestions(obsoleteSuggestedWords, typedWord); 17519fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka } 1752979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 17534a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 1754d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard public void showSuggestions(final SuggestedWords suggestedWords, final CharSequence typedWord) { 1755d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard final CharSequence autoCorrection; 17567e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestedWords.size() > 0) { 175768823ae08e820f0951447ed12c1bd32a24333d2eJean Chalard if (suggestedWords.hasAutoCorrectionWord()) { 1758d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = suggestedWords.getWord(1); 1759923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1760d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = typedWord; 1761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1763d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = null; 1764923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1765d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard mWordComposer.setAutoCorrection(autoCorrection); 17669b01890254c62a30b079bd9f79a30f9541faf11bJean Chalard final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); 1767dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setSuggestions(suggestedWords, isAutoCorrection); 1768dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 1769913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1770923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1771923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17725475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void commitCurrentAutoCorrection(final int separatorCodePoint) { 1773913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Complete any pending suggestions query first 1774d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka if (mHandler.hasPendingUpdateSuggestions()) { 1775d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.cancelUpdateSuggestions(); 1776923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project updateSuggestions(); 1777923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1778117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); 1779117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard if (autoCorrection != null) { 1780117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard final String typedWord = mWordComposer.getTypedWord(); 178146798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard if (TextUtils.isEmpty(typedWord)) { 178246798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard throw new RuntimeException("We have an auto-correction but the typed word " 178346798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard + "is empty? Impossible! I must commit suicide."); 178446798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard } 1785f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); 178660adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1787d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_commitCurrentAutoCorrection(typedWord, 178860adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge autoCorrection.toString()); 178960adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge } 17904733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 179166bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, 179266bb563535dbe3672f99f75bd71763a551444867Jean Chalard separatorCodePoint); 17935475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!typedWord.equals(autoCorrection)) { 17941c6cf26c3705e845418a29718c034598b52293ccJean Chalard // This will make the correction flash for a short while as a visual clue 17951c6cf26c3705e845418a29718c034598b52293ccJean Chalard // to the user that auto-correction happened. 17965475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCorrection( 17975475b38328171a0841ae18074bd45380ec567e90Jean Chalard new CorrectionInfo(mLastSelectionEnd - typedWord.length(), 179896fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasa typedWord, autoCorrection)); 17991c6cf26c3705e845418a29718c034598b52293ccJean Chalard } 1800923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1803c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 18049bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge public void pickSuggestionManually(final int index, final CharSequence suggestion, 18059bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge int x, int y) { 18065475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.beginBatchEdit(getCurrentInputConnection()); 18075475b38328171a0841ae18074bd45380ec567e90Jean Chalard pickSuggestionManuallyWhileInBatchEdit(index, suggestion, x, y); 18085475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 1809d4cacb1e41263ea4d78e7328f9d7ee173b79c4eaJean Chalard } 18104f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett 1811d4cacb1e41263ea4d78e7328f9d7ee173b79c4eaJean Chalard public void pickSuggestionManuallyWhileInBatchEdit(final int index, 18125475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence suggestion, final int x, final int y) { 1813d4cacb1e41263ea4d78e7328f9d7ee173b79c4eaJean Chalard final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); 1814551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput 1815551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard if (suggestion.length() == 1 && isShowingPunctuationList()) { 1816551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Word separators are suggested before the user inputs something. 1817551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // So, LatinImeLogger logs "" as a user's input. 1818551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); 1819551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. 1820551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 1821551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, x, y); 1822551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard } 1823551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard final int primaryCode = suggestion.charAt(0); 1824551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard onCodeInput(primaryCode, 1825551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, 1826551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); 1827551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard return; 1828551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard } 1829551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard 1830845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) { 1831845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard int firstChar = Character.codePointAt(suggestion, 0); 1832297e6d590bd957577c335aa8713a786145a70288Jean Chalard if ((!mCurrentSettings.isWeakSpaceStripper(firstChar)) 1833297e6d590bd957577c335aa8713a786145a70288Jean Chalard && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) { 1834845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard sendKeyCodePoint(Keyboard.CODE_SPACE); 1835845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 1836845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 1837845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard 1838dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn 1839dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mApplicationSpecifiedCompletions != null 18401b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka && index >= 0 && index < mApplicationSpecifiedCompletions.length) { 1841913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) { 1842913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.clear(); 1843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1844b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1845611a5bdf650f7bc54bf40176f84f1cd9c87aa9aaJean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 18465475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; 18475475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCompletion(completionInfo); 18485475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 18495475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index, 18505475b38328171a0841ae18074bd45380ec567e90Jean Chalard completionInfo.getText(), x, y); 18519a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 1852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 18546a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1855af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // We need to log before we commit, because the word composer will store away the user 1856af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // typed word. 18579bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge final String replacedWord = mWordComposer.getTypedWord().toString(); 18589bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge LatinImeLogger.logOnManualSuggestion(replacedWord, 18598cc8f26adfe0f06cebc697dac43a856326cf7afcTadashi G. Takaoka suggestion.toString(), index, suggestedWords); 18609bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 18619bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, x, y); 18629bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge } 18634733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 186466bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, 186566bb563535dbe3672f99f75bd71763a551444867Jean Chalard LastComposedWord.NOT_A_SEPARATOR); 186629a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard // Don't allow cancellation of manual pick 186729a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard mLastComposedWord.deactivate(); 1868fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1869fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // TODO: is this necessary? 1870fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mKeyboardSwitcher.updateShiftState(); 1871979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1872c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // We should show the "Touch again to save" hint if the user pressed the first entry 1873c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND either: 18747f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is no dictionary (we know that because we tried to load it => null != mSuggest 1875c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND mSuggest.hasMainDictionary() is false) 18767f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is a dictionary and the word is not in it 18777f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // Please note that if mSuggest is null, it means that everything is off: suggestion 18787f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // and correction, so we shouldn't try to show the hint 18797f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // We used to look at mCorrectionMode here, but showing the hint should have nothing 18807f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // to do with the autocorrection setting. 1881bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null 1882bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If there is no dictionary the hint should be shown. 1883c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa && (!mSuggest.hasMainDictionary() 1884bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If "suggestion" is not in the dictionary, the hint should be shown. 1885bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok || !AutoCorrection.isValidWord( 1886bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok mSuggest.getUnigramDictionaries(), suggestion, true)); 1887b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 1888406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE, 1889406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard WordComposer.NOT_A_COORDINATE); 1890777118a40a363ccab69a00016d3156066513cb78Jean Chalard if (!showingAddToDictionaryHint) { 1891364da8c618303a7764595d2c15ee034a7671365dKen Wakasa // If we're not showing the "Touch again to save", then show corrections again. 1892979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // In case the cursor position doesn't change, make sure we show the suggestions again. 189341ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard updateBigramPredictions(); 189441ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // Updating the predictions right away may be slow and feel unresponsive on slower 189541ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // terminals. On the other hand if we just postUpdateBigramPredictions() it will 189641ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // take a noticeable delay to update them which may feel uneasy. 189795a6e58ebcd8f44b970a8238cf30e48b10fc4b61Jean Chalard } else { 189888562bec54658840dcce352127bdc15705c20a89Jean Chalard if (mIsUserDictionaryAvailable) { 1899644d33d60ea5a87501274488013d65f55238895eKen Wakasa mSuggestionsView.showAddToDictionaryHint( 1900297e6d590bd957577c335aa8713a786145a70288Jean Chalard suggestion, mCurrentSettings.mHintToSaveText); 1901ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka } else { 1902ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1903ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka } 190466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 1905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1906a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1907979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 19088558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa * Commits the chosen word to the text field and saves it for later retrieval. 1909979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 1910c54d558e2e70bdfb2c1078cae7b88440d421dc67satok private void commitChosenWord(final CharSequence chosenWord, final int commitType, 191166bb563535dbe3672f99f75bd71763a551444867Jean Chalard final int separatorCode) { 1912297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.mEnableSuggestionSpanInsertion) { 19135475b38328171a0841ae18074bd45380ec567e90Jean Chalard final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); 19145475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( 19155475b38328171a0841ae18074bd45380ec567e90Jean Chalard this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 19165475b38328171a0841ae18074bd45380ec567e90Jean Chalard 1); 19175475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 19185475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_commitText(chosenWord); 19195475b38328171a0841ae18074bd45380ec567e90Jean Chalard } 19205475b38328171a0841ae18074bd45380ec567e90Jean Chalard } else { 19215475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(chosenWord, 1); 19225475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 19235475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_commitText(chosenWord); 19241531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard } 1925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1926c54d558e2e70bdfb2c1078cae7b88440d421dc67satok // Add the word to the user history dictionary 1927c54d558e2e70bdfb2c1078cae7b88440d421dc67satok final CharSequence prevWord = addToUserHistoryDictionary(chosenWord); 19280fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // TODO: figure out here if this is an auto-correct or if the best word is actually 19290fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // what user typed. Note: currently this is done much later in 1930bdf89ce5feedb03e67b43f530b1eb9bd44203c63Jean Chalard // LastComposedWord#didCommitTypedWord by string equality of the remembered 19310fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // strings. 1932c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), 1933c54d558e2e70bdfb2c1078cae7b88440d421dc67satok separatorCode, prevWord); 1934923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 193641ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard public void updateBigramPredictions() { 193789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (mSuggest == null || !isSuggestionsRequested()) 193889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard return; 193989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 1940297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mCurrentSettings.mBigramPredictionEnabled) { 1941cb3320179d39a7983874697a0aa428b127675c9dJean Chalard setPunctuationSuggestions(); 1942cb3320179d39a7983874697a0aa428b127675c9dJean Chalard return; 1943cb3320179d39a7983874697a0aa428b127675c9dJean Chalard } 1944cb3320179d39a7983874697a0aa428b127675c9dJean Chalard 19458e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard final SuggestedWords suggestedWords; 1946297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { 1947297e6d590bd957577c335aa8713a786145a70288Jean Chalard final CharSequence prevWord = mConnection.getThisWord(mCurrentSettings.mWordSeparators); 19480cf422fbb763e2672fb2f9e8e1e8af91d2e87cb3Jean Chalard if (!TextUtils.isEmpty(prevWord)) { 19495b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard suggestedWords = mSuggest.getBigramPredictions(prevWord); 19500cf422fbb763e2672fb2f9e8e1e8af91d2e87cb3Jean Chalard } else { 19518e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard suggestedWords = null; 19520cf422fbb763e2672fb2f9e8e1e8af91d2e87cb3Jean Chalard } 1953a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard } else { 19548e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard suggestedWords = null; 1955a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard } 195689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 19578e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard if (null != suggestedWords && suggestedWords.size() > 0) { 195889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Explicitly supply an empty typed word (the no-second-arg version of 195989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // showSuggestions will retrieve the word near the cursor, we don't want that here) 19608e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard showSuggestions(suggestedWords, ""); 196189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 196289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (!isShowingPunctuationList()) setPunctuationSuggestions(); 196389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 196489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 196589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 19667a8dac55278cedd838be325f56b4c52d973c61f5satok public void setPunctuationSuggestions() { 1967297e6d590bd957577c335aa8713a786145a70288Jean Chalard setSuggestions(mCurrentSettings.mSuggestPuncList, false); 19687204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1969913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 19706a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 19716a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1972c54d558e2e70bdfb2c1078cae7b88440d421dc67satok private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) { 1973c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (TextUtils.isEmpty(suggestion)) return null; 1974bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 19750c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be 19760c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // adding words in situations where the user or application really didn't 19770c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // want corrections enabled or learned. 1978297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!(mCurrentSettings.mCorrectionMode == Suggest.CORRECTION_FULL 1979297e6d590bd957577c335aa8713a786145a70288Jean Chalard || mCurrentSettings.mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) { 1980c54d558e2e70bdfb2c1078cae7b88440d421dc67satok return null; 1981979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1982bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 19839ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard if (mUserHistoryDictionary != null) { 198402308bec632a5df23325c916bffec5def16b22b4Jean Chalard final CharSequence prevWord 1985297e6d590bd957577c335aa8713a786145a70288Jean Chalard = mConnection.getPreviousWord(mCurrentSettings.mWordSeparators); 198671f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard final String secondWord; 198771f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) { 19886a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka secondWord = suggestion.toString().toLowerCase( 19896a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSubtypeSwitcher.getCurrentSubtypeLocale()); 199071f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } else { 199171f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard secondWord = suggestion.toString(); 199271f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } 1993c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka // We demote unrecognized word and words with 0-frequency (assuming they would be 1994c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka // profanity etc.) by specifying them as "invalid". 1995c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka final int maxFreq = AutoCorrection.getMaxFrequency( 1996c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka mSuggest.getUnigramDictionaries(), suggestion); 19979ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard mUserHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(), 1998c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka secondWord, maxFreq > 0); 1999c54d558e2e70bdfb2c1078cae7b88440d421dc67satok return prevWord; 200032e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 2001c54d558e2e70bdfb2c1078cae7b88440d421dc67satok return null; 200232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 200332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani 20046b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 20056b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Check if the cursor is actually at the end of a word. If so, restart suggestions on this 20066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * word, else do nothing. 20076b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 20085475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() { 2009747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings); 2010747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard if (null != word) { 2011747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard restartSuggestionsOnWordBeforeCursor(word); 2012fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard } 20136b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 20146b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20155475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursor(final CharSequence word) { 20163708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); 2017d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int length = word.length(); 20185475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(length, 0); 2019d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2020d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(length); 2021d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 20225475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(word, 1); 20236b1f500da451de56932a8b2a99c63857994ece85Jean Chalard mHandler.postUpdateSuggestions(); 20246b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 20256b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20265475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void revertCommit() { 2027c54d558e2e70bdfb2c1078cae7b88440d421dc67satok final CharSequence previousWord = mLastComposedWord.mPrevWord; 2028b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard final String originallyTypedWord = mLastComposedWord.mTypedWord; 2029cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final CharSequence committedWord = mLastComposedWord.mCommittedWord; 2030cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final int cancelLength = committedWord.length(); 2031ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok final int separatorLength = LastComposedWord.getSeparatorLength( 2032193d23f40e1556074f323b7bd9695759f4798efeJean Chalard mLastComposedWord.mSeparatorCode); 2033193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // TODO: should we check our saved separator against the actual contents of the text view? 2034d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int deleteLength = cancelLength + separatorLength; 2035890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2036b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard if (mWordComposer.isComposingWord()) { 20375935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit, but we are composing a word"); 2038b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard } 2039890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard final String wordBeforeCursor = 20405475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.getTextBeforeCursor(deleteLength, 0) 2041193d23f40e1556074f323b7bd9695759f4798efeJean Chalard .subSequence(0, cancelLength).toString(); 2042cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard if (!TextUtils.equals(committedWord, wordBeforeCursor)) { 20435935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit check failed: we thought we were " 2044cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard + "reverting \"" + committedWord 2045890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); 2046890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 20478558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa } 20485475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(deleteLength, 0); 2049d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2050d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(deleteLength); 2051d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 2052c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { 2053c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mUserHistoryDictionary.cancelAddingUserHistory( 2054c54d558e2e70bdfb2c1078cae7b88440d421dc67satok previousWord.toString(), committedWord.toString()); 2055c54d558e2e70bdfb2c1078cae7b88440d421dc67satok } 2056193d23f40e1556074f323b7bd9695759f4798efeJean Chalard if (0 == separatorLength || mLastComposedWord.didCommitTypedWord()) { 2057193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // This is the case when we cancel a manual pick. 2058193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // We should restart suggestion on the word right away. 205932f0af1fc48f67907f0e731e18359f29e2b1df14Jean Chalard mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); 20605475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(originallyTypedWord, 1); 2061193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } else { 20625475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(originallyTypedWord, 1); 2063193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // Re-insert the separator 2064193d23f40e1556074f323b7bd9695759f4798efeJean Chalard sendKeyCodePoint(mLastComposedWord.mSeparatorCode); 2065193d23f40e1556074f323b7bd9695759f4798efeJean Chalard Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode, WordComposer.NOT_A_COORDINATE, 2066193d23f40e1556074f323b7bd9695759f4798efeJean Chalard WordComposer.NOT_A_COORDINATE); 2067d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2068d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_revertCommit(originallyTypedWord); 2069d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 2070193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // Don't restart suggestion yet. We'll restart if the user deletes the 2071193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // separator. 2072193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } 2073b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 2074890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard mHandler.cancelUpdateBigramPredictions(); 2075890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard mHandler.postUpdateSuggestions(); 2076890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2077890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 20785475b38328171a0841ae18074bd45380ec567e90Jean Chalard private boolean revertDoubleSpaceWhileInBatchEdit() { 20794733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Here we test whether we indeed have a period and a space before us. This should not 20804733609947c0ec74e460bd714fffca0518ade93aJean Chalard // be needed, but it's there just in case something went wrong. 20815475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(2, 0); 20828ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard if (!". ".equals(textBeforeCursor)) { 208351fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // Theoretically we should not be coming here if there isn't ". " before the 208451fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // cursor, but the application may be changing the text while we are typing, so 208551fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // anything goes. We should not crash. 208651fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard Log.d(TAG, "Tried to revert double-space combo but we didn't find " 20878ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard + "\". \" just before the cursor."); 208851fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard return false; 20898ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard } 20905475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 2091d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2092d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(2); 2093d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 20945475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(" ", 1); 2095d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2096d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_revertDoubleSpaceWhileInBatchEdit(); 2097d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 20984733609947c0ec74e460bd714fffca0518ade93aJean Chalard return true; 20994733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 21004733609947c0ec74e460bd714fffca0518ade93aJean Chalard 21015475b38328171a0841ae18074bd45380ec567e90Jean Chalard private boolean revertSwapPunctuation() { 2102120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Here we test whether we indeed have a space and something else before us. This should not 2103120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // be needed, but it's there just in case something went wrong. 21045475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(2, 0); 2105120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to 2106120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // enter surrogate pairs this code will have been removed. 21078be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard if (TextUtils.isEmpty(textBeforeCursor) 21088be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard || (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))) { 21098be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard // We may only come here if the application is changing the text while we are typing. 21108be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard // This is quite a broken case, but not logically impossible, so we shouldn't crash, 21118be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard // but some debugging log may be in order. 21128be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard Log.d(TAG, "Tried to revert a swap of punctuation but we didn't " 21138ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard + "find a space just before the cursor."); 21148be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard return false; 21158ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard } 21165475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 2117d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2118d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(2); 2119d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 21205475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(" " + textBeforeCursor.subSequence(0, 1), 1); 2121d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2122d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_revertSwapPunctuation(); 2123d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 2124120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 2125120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 2126120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 2127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean isWordSeparator(int code) { 2128297e6d590bd957577c335aa8713a786145a70288Jean Chalard return mCurrentSettings.isWordSeparator(code); 2129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean preferCapitalization() { 21329318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa return mWordComposer.isFirstCharCapitalized(); 2133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 213588fc9d44186120f9edc5cf7ec0e2af85260fed04satok // Notify that language or mode have been changed and toggleLanguage will update KeyboardID 2136c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka // according to new language or mode. 2137c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka public void onRefreshKeyboard() { 21381e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // When the device locale is changed in SetupWizard etc., this method may get called via 21391e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // onConfigurationChanged before SoftInputWindow is shown. 21401e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka if (mKeyboardSwitcher.getKeyboardView() != null) { 21411e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // Reload keyboard because the current language has been changed. 2142297e6d590bd957577c335aa8713a786145a70288Jean Chalard mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings); 21431e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka } 21440ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 214517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 2146b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // Since we just changed languages, we should re-evaluate suggestions with whatever word 2147b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // we are currently composing. If we are not composing anything, we may want to display 2148b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // predictions or punctuation signs (which is done by updateBigramPredictions anyway). 2149297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mConnection.isCursorTouchingWord(mCurrentSettings)) { 2150b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard mHandler.postUpdateSuggestions(); 2151b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard } else { 2152b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard mHandler.postUpdateBigramPredictions(); 2153b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard } 215436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 215536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 215678e3977e90a9946a057dfb628f99683e386015bdTadashi G. Takaoka // TODO: Remove this method from {@link LatinIME} and move {@link FeedbackManager} to 215778e3977e90a9946a057dfb628f99683e386015bdTadashi G. Takaoka // {@link KeyboardSwitcher}. 2158564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard public void hapticAndAudioFeedback(final int primaryCode) { 2159544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard mFeedbackManager.hapticAndAudioFeedback(primaryCode, mKeyboardSwitcher.getKeyboardView()); 2160d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka } 2161d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka 21625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 21632a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onPressKey(int primaryCode) { 2164a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mKeyboardSwitcher.onPressKey(primaryCode); 2165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 21675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 21682a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onReleaseKey(int primaryCode, boolean withSliding) { 21692a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); 21708d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 21718d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv // If accessibility is on, ensure the user receives keyboard state updates. 21728d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 21738d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (primaryCode) { 21748d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case Keyboard.CODE_SHIFT: 21758d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); 21768d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 21778d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 21788d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); 21798d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 21808d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 21818d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2182978c96aa995015658070346b60826a3a34fdaf84Jean Chalard 2183978c96aa995015658070346b60826a3a34fdaf84Jean Chalard if (Keyboard.CODE_DELETE == primaryCode) { 2184978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // This is a stopgap solution to avoid leaving a high surrogate alone in a text view. 2185978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // In the future, we need to deprecate deteleSurroundingText() and have a surrogate 2186978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // pair-friendly way of deleting characters in InputConnection. 21875475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastChar = mConnection.getTextBeforeCursor(1, 0); 21885475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) { 21895475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 2190978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2191978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2193a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2194123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka // receive ringer mode change and network state change. 2195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private BroadcastReceiver mReceiver = new BroadcastReceiver() { 2196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 2197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onReceive(Context context, Intent intent) { 2198123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final String action = intent.getAction(); 2199564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2200123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka mSubtypeSwitcher.onNetworkStateChanged(intent); 220121af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 220221af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard mFeedbackManager.onRingerModeChanged(); 2203123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } 2204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 2206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2207c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka private void launchSettings() { 2208c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka launchSettingsClass(SettingsActivity.class); 2209466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2210466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2211bf96661d33d0126adb60a48880ceba1ff055d4a4satok public void launchDebugSettings() { 2212c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka launchSettingsClass(DebugSettingsActivity.class); 2213bf96661d33d0126adb60a48880ceba1ff055d4a4satok } 2214bf96661d33d0126adb60a48880ceba1ff055d4a4satok 2215c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka private void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) { 2216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project handleClose(); 2217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Intent intent = new Intent(); 2218466741d8a78965b8509bf527344f289e50873092Mike LeBeau intent.setClass(LatinIME.this, settingsClass); 2219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project startActivity(intent); 2221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22232fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showSubtypeSelectorAndSettings() { 222485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 222585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 222685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka // TODO: Should use new string "Select active input modes". 222785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.language_selection_title), 222885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.english_ime_settings), 222985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 223055d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka final Context context = this; 223185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 22322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka @Override 22332fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka public void onClick(DialogInterface di, int position) { 22342fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka di.dismiss(); 22352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka switch (position) { 223685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 22372cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok Intent intent = CompatUtils.getInputLanguageSelectionIntent( 223855d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka ImfUtils.getInputMethodIdOfThisIme(context), 22392a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Intent.FLAG_ACTIVITY_NEW_TASK 22402fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 22412fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 22422fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka startActivity(intent); 22432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2244aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa case 1: 2245aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa launchSettings(); 2246aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa break; 22472fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 22482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 224985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2250bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2251bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2252bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2253724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge showOptionDialog(builder.create()); 22542fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 2255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2256724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge /* package */ void showOptionDialog(AlertDialog dialog) { 22576a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken(); 225813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka if (windowToken == null) return; 225913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 226013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCancelable(true); 226113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCanceledOnTouchOutside(true); 226213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 226313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final Window window = dialog.getWindow(); 226413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final WindowManager.LayoutParams lp = window.getAttributes(); 226513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.token = windowToken; 226613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 226713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.setAttributes(lp); 226813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 226913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 227013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka mOptionsDialog = dialog; 227113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.show(); 227213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka } 227313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 22747e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 22757e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 2276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.dump(fd, fout, args); 2277a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project final Printer p = new PrintWriterPrinter(fout); 2279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println("LatinIME state :"); 22803708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2281df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; 2282df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka p.println(" Keyboard mode = " + keyboardMode); 2283dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn); 2284297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mCorrectionMode=" + mCurrentSettings.mCorrectionMode); 22854d0f03bd66742ee292da81a3e025e119f28b6940Jean Chalard p.println(" isComposingWord=" + mWordComposer.isComposingWord()); 2286297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mAutoCorrectEnabled=" + mCurrentSettings.mAutoCorrectEnabled); 2287297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mSoundOn=" + mCurrentSettings.mSoundOn); 2288297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn); 2289297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn); 22906fa003ee234c6e2ca6cd9ec555221ac5c71a5405Jean Chalard p.println(" mInputAttributes=" + mInputAttributes.toString()); 2291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 2293