1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * 48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at 7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * 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 118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and 148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under 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 233c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridgeimport android.app.Activity; 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog; 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver; 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface; 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent; 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter; 30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences; 317058b02a9c798c21b169b778be2befc7739f4e9bJean Chalardimport android.content.pm.PackageInfo; 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration; 3336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources; 34c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.graphics.Rect; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService; 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager; 37123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager; 38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug; 39f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaokaimport android.os.Handler; 40f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaokaimport android.os.HandlerThread; 4181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaokaimport android.os.IBinder; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager; 45e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType; 466a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalardimport android.text.SpannableString; 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils; 486a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalardimport android.text.style.SuggestionSpan; 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log; 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter; 51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer; 524e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyCharacterMap; 534e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyEvent; 54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 55c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.view.ViewGroup.LayoutParams; 5613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.Window; 5713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.WindowManager; 58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo; 5996fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasaimport android.view.inputmethod.CorrectionInfo; 60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo; 619cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 62c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 635ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils; 648d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 6515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting; 667058b02a9c798c21b169b778be2befc7739f4e9bJean Chalardimport com.android.inputmethod.compat.AppWorkaroundsUtils; 67fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasaimport com.android.inputmethod.compat.InputMethodServiceCompatUtils; 681fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils; 691061bfdb34bbcb63bf0046eec42313d264ac33faJean Chalardimport com.android.inputmethod.dictionarypack.DictionaryPackConstants; 70cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalardimport com.android.inputmethod.event.EventInterpreter; 715c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 72c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 73c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 746b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 75c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 76c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView; 776a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalardimport com.android.inputmethod.latin.RichInputConnection.Range; 789310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 7987cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataokaimport com.android.inputmethod.latin.Utils.Stats; 80c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 814702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionStripView; 826b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 84466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor; 85466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter; 864ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalardimport java.util.ArrayList; 87466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale; 88976a42b873215a669fe22709960aa1259292d75cJean Chalardimport java.util.TreeSet; 89466741d8a78965b8509bf527344f289e50873092Mike LeBeau 90923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 91923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard. 92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 93b1e37e4a478a577c59930767148e50f8f45af21fJean Chalardpublic class LatinIME extends InputMethodService implements KeyboardActionListener, 947058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard SuggestionStripView.Listener, TargetPackageInfoGetterTask.OnTargetPackageInfoKnownListener, 95369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka Suggest.SuggestInitializationListener { 968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka private static final String TAG = LatinIME.class.getSimpleName(); 97409220583333bdf06290dd9fd42f91b5c0d1b11asatok private static final boolean TRACE = false; 989e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka private static boolean DEBUG; 99a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1009e347d3d448e48229c46aad394ec9bd60cd5807bsatok private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; 101fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa 102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // How many continuous deletes at which to start deleting at a higher speed. 103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int DELETE_ACCELERATE_AT = 20; 104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Key events coming any faster than this are long-presses. 105d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani private static final int QUICK_PRESS = 200; 106a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 10759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private static final int PENDING_IMS_CALLBACK_DURATION = 800; 108055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 109cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /** 110cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * The name of the scheme used by the Package Manager to warn of a new package installation, 111cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * replacement or removal. 112cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard */ 113cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private static final String SCHEME_PACKAGE = "package"; 114cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 115fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_NONE = 0; 116120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Double space: the state where the user pressed space twice quickly, which LatinIME 117120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // resolved as period-space. Undoing this converts the period to a space. 118fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_DOUBLE = 1; 119b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip 120b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // have just been swapped. Undoing this swaps them back; the space is still considered weak. 121120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; 122fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak 123fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // spaces happen when the user presses space, accepting the current suggestion (whether 124fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // it's an auto-correction or not). 125fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_WEAK = 3; 126fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom space: a not-yet-inserted space that should get inserted on the next input, 127fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // character provided it's not a separator. If it's a separator, the phantom space is dropped. 128fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom spaces happen when a user chooses a word from the suggestion strip. 129fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_PHANTOM = 4; 130120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 131120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Current space state of the input method. This can be any of the above constants. 132120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private int mSpaceState; 133126698fdd256a2e3734634d3b923cabd800064baJean Chalard 134ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka private final Settings mSettings; 13517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 136d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka private View mExtractArea; 137abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka private View mKeyPreviewBackingView; 138913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private View mSuggestionsContainer; 1394702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka private SuggestionStripView mSuggestionStripView; 140abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard // Never null 141abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; 14215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting Suggest mSuggest; 1431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private CompletionInfo[] mApplicationSpecifiedCompletions; 1447058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard private AppWorkaroundsUtils mAppWorkAroundsUtils = new AppWorkaroundsUtils(); 145a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private RichInputMethodManager mRichImm; 14715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; 14889ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard private final SubtypeSwitcher mSubtypeSwitcher; 1491931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka private final SubtypeState mSubtypeState = new SubtypeState(); 150cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // At start, create a default event interpreter that does nothing by passing it no decoder spec. 151cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // The event interpreter should never be null. 152997cba7decce9694b3c2f9487deb9710ebb19595Jean Chalard private EventInterpreter mEventInterpreter = new EventInterpreter(this); 153a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1546a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka private boolean mIsMainDictionaryAvailable; 15567fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private UserBinaryDictionary mUserDictionary; 1569ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard private UserHistoryDictionary mUserHistoryDictionary; 15788562bec54658840dcce352127bdc15705c20a89Jean Chalard private boolean mIsUserDictionaryAvailable; 15836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 1592692a8700737d8eed268039aa27b22a31669da08Jean Chalard private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 16018d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard private PositionalInfoForUserDictPendingAddition 16118d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard mPositionalInfoForUserDictPendingAddition = null; 16287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka private final WordComposer mWordComposer = new WordComposer(); 163a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka private final RichInputConnection mConnection = new RichInputConnection(this); 164b794e904a3586ac5f2d31fb24d5a1a8f9aa964b8Jean Chalard private final RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(); 165409220583333bdf06290dd9fd42f91b5c0d1b11asatok 166979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Keep track of the last selection range to decide if we need to show word alternatives 16777da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private static final int NOT_A_CURSOR_POSITION = -1; 16877da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionStart = NOT_A_CURSOR_POSITION; 16977da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; 170979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1714733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't 1724733609947c0ec74e460bd714fffca0518ade93aJean Chalard // "expect" it, it means the user actually moved the cursor. 1734733609947c0ec74e460bd714fffca0518ade93aJean Chalard private boolean mExpectingUpdateSelection; 174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mDeleteCount; 175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private long mLastKeyTime; 176976a42b873215a669fe22709960aa1259292d75cJean Chalard private TreeSet<Long> mCurrentlyPressedHardwareKeys = CollectionUtils.newTreeSet(); 177a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 17838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Member variables for remembering the current device orientation. 17938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka private int mDisplayOrientation; 18038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 181cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Object for reacting to adding/removing a dictionary pack. 1829c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack 1839c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Service yet. 184cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private BroadcastReceiver mDictionaryPackInstallReceiver = 1859c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS 186710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa ? null : new DictionaryPackInstallBroadcastReceiver(this); 187cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 188dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Keeps track of most recently inserted text (multi-character key) for reverting 189bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String mEnteredText; 190dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 191b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // TODO: This boolean is persistent state and causes large side effects at unexpected times. 192b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // Find a way to remove it for readability. 19370852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard private boolean mIsAutoCorrectionIndicatorOn; 194604d80c67185954d4691ac775be59c499eee3b1csatok 19513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka private AlertDialog mOptionsDialog; 19613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 197fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa private final boolean mIsHardwareAcceleratedDrawingEnabled; 198fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa 1994f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public final UIHandler mHandler = new UIHandler(this); 200d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 201a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka public static final class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { 20227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_UPDATE_SHIFT_STATE = 0; 20327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_PENDING_IMS_CALLBACK = 1; 20427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION_STRIP = 2; 205f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3; 2066a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard private static final int MSG_RESUME_SUGGESTIONS = 4; 207f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 208f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; 2094c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka 21010dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateSuggestions; 21110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateShiftState; 2122b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private long mDoubleSpacePeriodTimeout; 2132b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private long mDoubleSpacePeriodTimerStart; 21438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 215f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public UIHandler(final LatinIME outerInstance) { 2164f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 21710dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka } 218175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 21910dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka public void onCreate() { 22010dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka final Resources res = getOuterInstance().getResources(); 221175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateSuggestions = 222175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_suggestions); 223175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateShiftState = 224175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_shift_state); 2252b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mDoubleSpacePeriodTimeout = 2262b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa res.getInteger(R.integer.config_double_space_period_timeout); 2274f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 2284f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 230f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void handleMessage(final Message msg) { 2314f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 2324f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; 233923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 234dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard case MSG_UPDATE_SUGGESTION_STRIP: 235259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka latinIme.updateSuggestionStrip(); 236d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 237d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SHIFT_STATE: 238de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka switcher.updateShiftState(); 239d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 240f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka case MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: 241f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords)msg.obj, 242f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT); 243f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka break; 2446a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard case MSG_RESUME_SUGGESTIONS: 2456a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard latinIme.restartSuggestionsOnWordTouchedByCursor(); 2466a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard break; 247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 249d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 250a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard public void postUpdateSuggestionStrip() { 251dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions); 252d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 253d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 2546a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard public void postResumeSuggestions() { 2559f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard removeMessages(MSG_RESUME_SUGGESTIONS); 2566a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions); 2576a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 2586a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 259d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard public void cancelUpdateSuggestionStrip() { 260dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard removeMessages(MSG_UPDATE_SUGGESTION_STRIP); 261d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 262d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 263d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public boolean hasPendingUpdateSuggestions() { 264dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard return hasMessages(MSG_UPDATE_SUGGESTION_STRIP); 265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 267beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void postUpdateShiftState() { 268d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 269175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); 270d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 271d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 272d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateShiftState() { 273d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 274d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 275d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 276f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, 277f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final boolean dismissGestureFloatingPreviewText) { 278f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); 279f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final int arg1 = dismissGestureFloatingPreviewText 280f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT : 0; 281f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1, 0, suggestedWords) 282f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka .sendToTarget(); 283f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 284f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 2852b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa public void startDoubleSpacePeriodTimer() { 2862b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mDoubleSpacePeriodTimerStart = SystemClock.uptimeMillis(); 287fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 288fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 2892b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa public void cancelDoubleSpacePeriodTimer() { 2902b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mDoubleSpacePeriodTimerStart = 0; 291fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 292fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 2932b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa public boolean isAcceptingDoubleSpacePeriod() { 2942b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa return SystemClock.uptimeMillis() - mDoubleSpacePeriodTimerStart 2952b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa < mDoubleSpacePeriodTimeout; 296fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 29738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 29859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Working variables for the following methods. 29959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mIsOrientationChanging; 3005fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard private boolean mPendingSuccessiveImsCallback; 30159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingStartInput; 30259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInputView; 30359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInput; 304e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private EditorInfo mAppliedEditorInfo; 30559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 30659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void startOrientationChanging() { 307dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka removeMessages(MSG_PENDING_IMS_CALLBACK); 308dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka resetPendingImsCallback(); 30959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = true; 310055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 311f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka if (latinIme.isInputViewShown()) { 312f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka latinIme.mKeyboardSwitcher.saveKeyboardState(); 313f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka } 31459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 31559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 31659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void resetPendingImsCallback() { 31759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = false; 31859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = false; 31959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = false; 32059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 32159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 322f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void executePendingImsCallback(final LatinIME latinIme, final EditorInfo editorInfo, 32359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka boolean restarting) { 32459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInputView) 32559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(mHasPendingFinishInput); 32659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInput) 32759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 32859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingStartInput) 329e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 33059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka resetPendingImsCallback(); 33159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 33259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 333f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInput(final EditorInfo editorInfo, final boolean restarting) { 33459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 33559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the second onStartInput after orientation changed. 33659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = true; 33759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 33859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mIsOrientationChanging && restarting) { 33959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // This is the first onStartInput after orientation changed. 34059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = false; 3415fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = true; 34259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 34359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 344e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 345e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 346055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 347055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 348055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 349f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) { 3506b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK) 3516b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { 352e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // Typically this is the second onStartInputView after orientation changed. 353e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 354e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } else { 3555fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard if (mPendingSuccessiveImsCallback) { 356e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // This is the first onStartInputView after orientation changed. 3575fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = false; 358e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 359e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), 360e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka PENDING_IMS_CALLBACK_DURATION); 361e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 362e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 363e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 364e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputViewInternal(editorInfo, restarting); 365e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = editorInfo; 366e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 36759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 36859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 369f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onFinishInputView(final boolean finishingInput) { 37059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 37159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInputView after orientation changed. 37259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = true; 37359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 37459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 37559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(finishingInput); 376e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = null; 37738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 37838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 379ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka 38059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 38159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 38259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInput after orientation changed. 38359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = true; 38459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 38559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 38659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka executePendingImsCallback(latinIme, null, false); 38759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 388ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 389ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 39038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 39138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 3921931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka static final class SubtypeState { 3931931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka private InputMethodSubtype mLastActiveSubtype; 3941931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka private boolean mCurrentSubtypeUsed; 3951931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 3961931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka public void currentSubtypeUsed() { 3971931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mCurrentSubtypeUsed = true; 3981931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 3991931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 4001931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka public void switchSubtype(final IBinder token, final RichInputMethodManager richImm) { 4011931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka final InputMethodSubtype currentSubtype = richImm.getInputMethodManager() 4021931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka .getCurrentInputMethodSubtype(); 4031931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype; 4041931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka final boolean currentSubtypeUsed = mCurrentSubtypeUsed; 4051931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka if (currentSubtypeUsed) { 4061931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mLastActiveSubtype = currentSubtype; 4071931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mCurrentSubtypeUsed = false; 4081931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 4091931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka if (currentSubtypeUsed 4101931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka && richImm.checkIfSubtypeBelongsToThisImeAndEnabled(lastActiveSubtype) 4111931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka && !currentSubtype.equals(lastActiveSubtype)) { 4121931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka richImm.setInputMethodAndSubtype(token, lastActiveSubtype); 4131931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka return; 4141931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 4151931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka richImm.switchToNextInputMethod(token, true /* onlyCurrentIme */); 4161931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 4171931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 4181931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 41989ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard public LatinIME() { 42089ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard super(); 421ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mSettings = Settings.getInstance(); 42289ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 42389ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mKeyboardSwitcher = KeyboardSwitcher.getInstance(); 424fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa mIsHardwareAcceleratedDrawingEnabled = 425fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa InputMethodServiceCompatUtils.enableHardwareAcceleration(this); 426fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled); 42789ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard } 42889ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard 4297e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 4307e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka public void onCreate() { 431ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka Settings.init(this); 432f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka LatinImeLogger.init(this); 433f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka RichInputMethodManager.init(this); 43485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka mRichImm = RichInputMethodManager.getInstance(); 435ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka SubtypeSwitcher.init(this); 436f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka KeyboardSwitcher.init(this); 437b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka AudioAndHapticFeedbackManager.init(this); 4382ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka AccessibilityUtils.init(this); 439363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 440923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onCreate(); 441363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 44210dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka mHandler.onCreate(); 4439e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka DEBUG = LatinImeLogger.sDBG; 444363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 445d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard // TODO: Resolve mutual dependencies of {@link #loadSettings()} and {@link #initSuggest()}. 44628f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa loadSettings(); 4471f05cf6dab45c21d1ed334247929434d97c40584Tadashi G. Takaoka initSuggest(); 448979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 4499c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 450b094372bd68b2f1b1e62c48cc18503a60b6686b7Kurt Partridge ResearchLogger.getInstance().init(this, mKeyboardSwitcher, mSuggest); 45163bc2795967ddf99d3ac57e61153f8b2faa649acKurt Partridge } 452ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mDisplayOrientation = getResources().getConfiguration().orientation; 453b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 454cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Register to receive ringer mode change and network state change. 455cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Also receive installation and removal of a dictionary pack. 456123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final IntentFilter filter = new IntentFilter(); 457123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 45821af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project registerReceiver(mReceiver, filter); 460cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 4619c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack 4629c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Service yet. 4639c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (!ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 464710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa final IntentFilter packageFilter = new IntentFilter(); 465710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 466710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 467710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa packageFilter.addDataScheme(SCHEME_PACKAGE); 468710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa registerReceiver(mDictionaryPackInstallReceiver, packageFilter); 469710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa 470710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa final IntentFilter newDictFilter = new IntentFilter(); 4711061bfdb34bbcb63bf0046eec42313d264ac33faJean Chalard newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION); 472710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); 473710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa } 474923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 47536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 47617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // Has to be package-visible for unit tests 47715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting 4789fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka void loadSettings() { 479ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 480b0561ae98063f83684706886490ba5670138fcccJean Chalard final InputAttributes inputAttributes = 481b0561ae98063f83684706886490ba5670138fcccJean Chalard new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode()); 482ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mSettings.loadSettings(locale, inputAttributes); 483d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard // May need to reset the contacts dictionary depending on the user settings. 48414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); 48517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 48617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 4878335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 488369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka @Override 489f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onUpdateMainDictionaryAvailability(final boolean isMainDictionaryAvailable) { 490369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka mIsMainDictionaryAvailable = isMainDictionaryAvailable; 4918335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 4928335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka if (mainKeyboardView != null) { 4938335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka mainKeyboardView.setMainDictionaryAvailability(isMainDictionaryAvailable); 4948335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 495369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka } 496369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka 4970ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private void initSuggest() { 4986a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 4996a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final String localeStr = subtypeLocale.toString(); 50036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 50167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary oldContactsDictionary; 50278ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka if (mSuggest != null) { 50378ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = mSuggest.getContactsDictionary(); 50478ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.close(); 50578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } else { 50678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = null; 50778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 508369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka mSuggest = new Suggest(this /* Context */, subtypeLocale, 509369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka this /* SuggestInitializationListener */); 510ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().mCorrectionEnabled) { 511ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mSuggest.setAutoCorrectionThreshold(mSettings.getCurrent().mAutoCorrectionThreshold); 51278ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 513e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 5146a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 5159c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5166080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge ResearchLogger.getInstance().initSuggest(mSuggest); 5176080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge } 5186a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka 51967fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary = new UserBinaryDictionary(this, localeStr); 52067fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); 52178ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserDictionary(mUserDictionary); 522e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 52378ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka resetContactsDictionary(oldContactsDictionary); 524e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 525ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 526ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, prefs); 52778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); 528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 52936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 53014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard /** 53114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * Resets the contacts dictionary in mSuggest according to the user settings. 53214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 5332e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * This method takes an optional contacts dictionary to use when the locale hasn't changed 5342e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * since the contacts dictionary can be opened or closed as necessary depending on the settings. 53514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 53614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * @param oldContactsDictionary an optional dictionary to use, or null 53714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard */ 53867fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { 539ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final boolean shouldSetDictionary = 540ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka (null != mSuggest && mSettings.getCurrent().mUseContactsDict); 54114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 54267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary dictionaryToUse; 54314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (!shouldSetDictionary) { 54414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the dictionary is closed. If it is already closed, this is a no-op, 54514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // so it's safe to call it anyways. 54614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != oldContactsDictionary) oldContactsDictionary.close(); 54714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = null; 54814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 5492e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 5502e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang if (null != oldContactsDictionary) { 55167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard if (!oldContactsDictionary.mLocale.equals(locale)) { 55267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // If the locale has changed then recreate the contacts dictionary. This 55367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // allows locale dependent rules for handling bigram name predictions. 55467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.close(); 55505efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, locale); 5562e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } else { 55767fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // Make sure the old contacts dictionary is opened. If it is already open, 55867fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // this is a no-op, so it's safe to call it anyways. 55967fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.reopen(this); 5602e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang dictionaryToUse = oldContactsDictionary; 5612e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } 56218222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } else { 56305efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, locale); 56418222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } 56514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 56614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 56714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != mSuggest) { 56814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard mSuggest.setContactsDictionary(dictionaryToUse); 56914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 570699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard } 571699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard 572cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /* package private */ void resetSuggestMainDict() { 5736a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 57479eefda0d3ab5e03c2d012ed8ea1898004781871Tadashi G. Takaoka mSuggest.resetMainDict(this, subtypeLocale, this /* SuggestInitializationListener */); 5756a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 576cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard } 577cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 578466741d8a78965b8509bf527344f289e50873092Mike LeBeau @Override 579466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onDestroy() { 580e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa if (mSuggest != null) { 581e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.close(); 582e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest = null; 583979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 584ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mSettings.onDestroy(); 585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project unregisterReceiver(mReceiver); 586841c295f3c99214f45924434d9c0bb5b4760578dTadashi G. Takaoka if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 5877e2c1e69bf5782db8f358c9baeb518130aad0315Kurt Partridge ResearchLogger.getInstance().onDestroy(); 5887e2c1e69bf5782db8f358c9baeb518130aad0315Kurt Partridge } 5899c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // TODO: The development-only-diagnostic version is not supported by the Dictionary Pack 5909c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // Service yet. 5919c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (!ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 592710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa unregisterReceiver(mDictionaryPackInstallReceiver); 593710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa } 594979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 595979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.onDestroy(); 596923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onDestroy(); 597923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 600f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onConfigurationChanged(final Configuration conf) { 601b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani // If orientation changed while predicting, commit the change 602f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka if (mDisplayOrientation != conf.orientation) { 603f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = conf.orientation; 604f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mHandler.startOrientationChanging(); 605f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 6065475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 6075475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.finishComposingText(); 6085475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 6090a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka if (isShowingOptionDialog()) { 6102fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka mOptionsDialog.dismiss(); 6110a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka } 612b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onConfigurationChanged(conf); 614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 615b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public View onCreateInputView() { 618622d6a5b1b3d6a9140765b868abf1cdf412bc4f3Tadashi G. Takaoka return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled); 6196c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka } 6206c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka 6216c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka @Override 622f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void setInputView(final View view) { 6236c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka super.setInputView(view); 624d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka mExtractArea = getWindow().getWindow().getDecorView() 625d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka .findViewById(android.R.id.extractArea); 626abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); 627913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer = view.findViewById(R.id.suggestions_container); 6284702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view); 6294702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) 6304702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.setListener(this, view); 631f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka if (LatinImeLogger.sVISUALDEBUG) { 632f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); 633f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka } 634923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 635923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 636923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 637f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void setCandidatesView(final View view) { 638c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka // To ensure that CandidatesView will never be set. 639c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return; 640923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 641923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 642a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker @Override 643f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInput(final EditorInfo editorInfo, final boolean restarting) { 644e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInput(editorInfo, restarting); 64559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 64659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 64759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 648f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) { 649e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInputView(editorInfo, restarting); 65059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 65159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 65259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 653f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onFinishInputView(final boolean finishingInput) { 65459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInputView(finishingInput); 65559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 65638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 65759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 65859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 65959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInput(); 66059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 66159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 6629cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka @Override 663f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) { 6644f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 6654f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 666f483225397ddbd130b415c26909fa47d24fac97aTadashi G. Takaoka mSubtypeSwitcher.onSubtypeChanged(subtype); 6679fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka loadKeyboard(); 6689cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka } 6699cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka 670f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) { 671e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInput(editorInfo, restarting); 67259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 67359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 6741cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka @SuppressWarnings("deprecation") 675f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restarting) { 676e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInputView(editorInfo, restarting); 67745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 67827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView(); 679ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final SettingsValues currentSettings = mSettings.getCurrent(); 6808e09172df1bb176cc899940862c56bed9b9aec4esatok 681ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (editorInfo == null) { 682ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.e(TAG, "Null EditorInfo in onStartInputView()"); 683ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (LatinImeLogger.sDBG) { 684ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok throw new NullPointerException("Null EditorInfo in onStartInputView()"); 685ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 686ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok return; 687ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 68889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (DEBUG) { 689ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.d(TAG, "onStartInputView: editorInfo:" 690ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok + String.format("inputType=0x%08x imeOptions=0x%08x", 691ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok editorInfo.inputType, editorInfo.imeOptions)); 692b6fb5eb391987f3e426649a892cdcbf781957f5asatok Log.d(TAG, "All caps = " 693b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) 694b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", sentence caps = " 695b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0) 696b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", word caps = " 697b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); 698910b73127fa207dd26ec8124000262523b0aac0csatok } 6999c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 700ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 701ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, prefs); 7029bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 7031cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { 7044f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 7054f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 7061cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); 7074f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 7081cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { 7094f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 7104f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 7114f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); 7124f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 7134f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka 7147058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard final PackageInfo packageInfo = 7157058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard TargetPackageInfoGetterTask.getCachedPackageInfo(editorInfo.packageName); 7167058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard mAppWorkAroundsUtils.setPackageInfo(packageInfo); 7177058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard if (null == packageInfo) { 7187058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard new TargetPackageInfoGetterTask(this /* context */, this /* listener */) 7191b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard .execute(editorInfo.packageName); 7201b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard } 721b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 7227ef235f53f2291f22ddf8c56be9860a218b25bbbTadashi G. Takaoka LatinImeLogger.onStartInputView(editorInfo); 723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In landscape mode, this method gets called without the input view being created. 72427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView == null) { 725923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 726923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 727923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 728b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette // Forward this event to the accessibility utilities, if enabled. 729b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); 730b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette if (accessUtils.isTouchExplorationEnabled()) { 73105384933097c1e9c35e8be5c03757d072e5ffa46alanv accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting); 732b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette } 733b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette 734ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka final boolean inputTypeChanged = !currentSettings.isSameInputType(editorInfo); 735e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard final boolean isDifferentTextField = !restarting || inputTypeChanged; 736e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard if (isDifferentTextField) { 737f483225397ddbd130b415c26909fa47d24fac97aTadashi G. Takaoka mSubtypeSwitcher.updateParametersOnStartInputView(); 738aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard } 7394ab730dbd34fad323063f2ffd31ce33de746668dsatok 740b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // The EditorInfo might have a flag that affects fullscreen mode. 741b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // Note: This call should be done by InputMethodService? 742b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka updateFullscreenMode(); 743ccc35f7fa74860a8d737a4e9ff01fc0168dd329dJean Chalard mApplicationSpecifiedCompletions = null; 744c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 74561cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // The app calling setText() has the effect of clearing the composing 74661cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // span, so we should reset our state unconditionally, even if restarting is true. 74761cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard mEnteredText = null; 74861cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 74961cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard mDeleteCount = 0; 75061cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard mSpaceState = SPACE_STATE_NONE; 751b794e904a3586ac5f2d31fb24d5a1a8f9aa964b8Jean Chalard mRecapitalizeStatus.deactivate(); 752976a42b873215a669fe22709960aa1259292d75cJean Chalard mCurrentlyPressedHardwareKeys.clear(); 75361cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard 754d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard // Note: the following does a round-trip IPC on the main thread: be careful 755d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 756d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard if (null != mSuggest && null != currentLocale && !currentLocale.equals(mSuggest.mLocale)) { 757d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard initSuggest(); 758d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard } 75961cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard if (mSuggestionStripView != null) { 76061cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // This will set the punctuation suggestions if next word suggestion is off; 76161cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // otherwise it will clear the suggestion strip. 76261cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard setPunctuationSuggestions(); 763549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka } 764abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard mSuggestedWords = SuggestedWords.EMPTY; 76517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 7669f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart, 7679f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard false /* shouldFinishComposition */); 7689d1c73ffd88cd1bfef3de048b0b3a9a7dfbcfa70Jean Chalard 769e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard if (isDifferentTextField) { 77027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 771aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard loadSettings(); 772c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 773ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka if (mSuggest != null && currentSettings.mCorrectionEnabled) { 774ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mSuggest.setAutoCorrectionThreshold(currentSettings.mAutoCorrectionThreshold); 775aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard } 776aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard 777ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka switcher.loadKeyboard(editorInfo, currentSettings); 7785d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa } else if (restarting) { 7795d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa // TODO: Come up with a more comprehensive way to reset the keyboard layout when 7805d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa // a keyboard layout set doesn't get reloaded in this method. 7815d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa switcher.resetKeyboardStateToAlphabet(); 782d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // In apps like Talk, we come here when the text is sent and the field gets emptied and 783d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // we need to re-evaluate the shift state, but not the whole layout which would be 784d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // disruptive. 785d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // Space state must be updated before calling updateShiftState 786d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka switcher.updateShiftState(); 787aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard } 788913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShownInternal( 789913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka isSuggestionsStripVisible(), /* needsInputViewShown */ false); 7908e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard 791aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard mLastSelectionStart = editorInfo.initialSelStart; 792aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard mLastSelectionEnd = editorInfo.initialSelEnd; 793aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard 7948e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 7952b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 796c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 7972be2d776649c9c0b3914135794ab7a7e92e753f9Tadashi G. Takaoka mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable); 798ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mainKeyboardView.setKeyPreviewPopupEnabled(currentSettings.mKeyPreviewPopupOn, 799ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka currentSettings.mKeyPreviewPopupDismissDelay); 800ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mainKeyboardView.setSlidingKeyInputPreviewEnabled( 801ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka currentSettings.mSlidingKeyInputPreviewEnabled); 802ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mainKeyboardView.setGestureHandlingEnabledByUser( 803ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka currentSettings.mGestureInputEnabled); 804ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka mainKeyboardView.setGesturePreviewMode(currentSettings.mGesturePreviewTrailEnabled, 805ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka currentSettings.mGestureFloatingPreviewTextEnabled); 806c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 80718d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // If we have a user dictionary addition in progress, we should check now if we should 80818d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // replace the previously committed string with the word that has actually been added 80918d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // to the user dictionary. 81018d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard if (null != mPositionalInfoForUserDictPendingAddition 81118d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard && mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord( 812d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard mConnection, editorInfo, mLastSelectionEnd, currentLocale)) { 81318d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard mPositionalInfoForUserDictPendingAddition = null; 81418d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard } 81518d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // If tryReplaceWithActualWord returns false, we don't know what word was 81618d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // added to the user dictionary yet, so we keep the data and defer processing. The word will 81718d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // be replaced when the user dictionary reports back with the actual word, which ends 81818d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // up calling #onWordAddedToUserDictionary() in this class. 81918d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard 820c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); 821c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 822c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 8237058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard // Callback for the TargetPackageInfoGetterTask 8247214617622fce8f3fea6620e782c16336260a2a3Jean Chalard @Override 8257058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard public void onTargetPackageInfoKnown(final PackageInfo info) { 8267058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard mAppWorkAroundsUtils.setPackageInfo(info); 827b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard } 828b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 829923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 830e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka public void onWindowHidden() { 831e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka super.onWindowHidden(); 832f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 83327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 83427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 83527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 836e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 837e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 83859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputInternal() { 839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onFinishInput(); 840a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 841979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 842f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 84327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 84427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 84527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 846466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 847466741d8a78965b8509bf527344f289e50873092Mike LeBeau 848f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void onFinishInputViewInternal(final boolean finishingInput) { 8496495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa super.onFinishInputView(finishingInput); 850055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardSwitcher.onFinishInputView(); 851f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 85227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 85327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.cancelAllMessages(); 85427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 855d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka // Remove pending messages related to update suggestions 856d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 857edbb65be3e5e391affbf47e134422ac1d1a4ae13Tadashi G. Takaoka resetComposingState(true /* alsoResetLastComposedWord */); 85887bc3a4a62b28f9c64ced813a9af531a563b6cd9Kurt Partridge // Notify ResearchLogger 8599c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 86087bc3a4a62b28f9c64ced813a9af531a563b6cd9Kurt Partridge ResearchLogger.latinIME_onFinishInputViewInternal(finishingInput, mLastSelectionStart, 86187bc3a4a62b28f9c64ced813a9af531a563b6cd9Kurt Partridge mLastSelectionEnd, getCurrentInputConnection()); 862606058f777de394d38b364a655cff36ccaf0d5d2Kurt Partridge } 8636495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa } 8646495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa 8656495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa @Override 866f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onUpdateSelection(final int oldSelStart, final int oldSelEnd, 867f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final int newSelStart, final int newSelEnd, 868f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final int composingSpanStart, final int composingSpanEnd) { 869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, 870104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard composingSpanStart, composingSpanEnd); 871466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (DEBUG) { 872466741d8a78965b8509bf527344f289e50873092Mike LeBeau Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart 873466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ose=" + oldSelEnd 874025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lss=" + mLastSelectionStart 875025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lse=" + mLastSelectionEnd 876466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nss=" + newSelStart 877466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nse=" + newSelEnd 878104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", cs=" + composingSpanStart 879104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", ce=" + composingSpanEnd); 880466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 8819c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 882d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge final boolean expectingUpdateSelectionFromLogger = 883d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.getAndClearLatinIMEExpectingUpdateSelection(); 8849bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, 8859bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, 886d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge composingSpanEnd, mExpectingUpdateSelection, 88702308bec632a5df23325c916bffec5def16b22b4Jean Chalard expectingUpdateSelectionFromLogger, mConnection); 888d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (expectingUpdateSelectionFromLogger) { 889e86054e5c2e4734d87d2fbf1eeba8c75fc888df0Jean Chalard // TODO: Investigate. Quitting now sounds wrong - we won't do the resetting work 890d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge return; 891d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 8929bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 893466741d8a78965b8509bf527344f289e50873092Mike LeBeau 894104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // TODO: refactor the following code to be less contrived. 895104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means 896104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // that the cursor is not at the end of the composing span, or there is a selection. 897104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place 898104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // as last time we were called (if there is a selection, it means the start hasn't 899104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // changed, so it's the end that did). 900104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean selectionChanged = (newSelStart != composingSpanEnd 901104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart; 902104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // if composingSpanStart and composingSpanEnd are -1, it means there is no composing 903104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // span in the view - we can use that to narrow down whether the cursor was moved 904104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // by us or not. If we are composing a word but there is no composing span, then 905104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // we know for sure the cursor moved while we were composing and we should reset 906104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // the state. 907104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1; 908b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // If the keyboard is not visible, we don't need to do all the housekeeping work, as it 909b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // will be reset when the keyboard shows up anyway. 910b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // TODO: revisit this when LatinIME supports hardware keyboards. 911b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // NOTE: the test harness subclasses LatinIME and overrides isInputViewShown(). 912b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // TODO: find a better way to simulate actual execution. 913b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard if (isInputViewShown() && !mExpectingUpdateSelection 9145ed88457bf9ef3305d4a5aa4ac05b513433ad0ddJean Chalard && !mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart)) { 915cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // TAKE CARE: there is a race condition when we enter this test even when the user 916cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // did not explicitly move the cursor. This happens when typing fast, where two keys 917cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // turn this flag on in succession and both onUpdateSelection() calls arrive after 918cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // the second one - the first call successfully avoids this test, but the second one 919104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // enters. For the moment we rely on noComposingSpan to further reduce the impact. 92051fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 9219a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // TODO: the following is probably better done in resetEntireInputState(). 9229a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // it should only happen when the cursor moved, and the very purpose of the 9239a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // test below is to narrow down whether this happened or not. Likewise with 924fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // the call to updateShiftState. 92551fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // We set this to NONE because after a cursor move, we don't want the space 92651fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // state-related special processing to kick in. 92751fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard mSpaceState = SPACE_STATE_NONE; 92851fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 9298a3d369840d6061692a19ceb1eb7267a50a9e056Jean Chalard if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) { 9306a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // If we are composing a word and moving the cursor, we would want to set a 9316a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // suggestion span for recorrection to work correctly. Unfortunately, that 9326a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // would involve the keyboard committing some new text, which would move the 9336a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // cursor back to where it was. Latin IME could then fix the position of the cursor 9346a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // again, but the asynchronous nature of the calls results in this wreaking havoc 9356a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // with selection on double tap and the like. 9366a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // Another option would be to send suggestions each time we set the composing 9376a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // text, but that is probably too expensive to do, so we decided to leave things 9386a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // as is. 93928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard resetEntireInputState(newSelStart); 9404c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 941beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 942aa3a96f3a1c5aeacefdfd6e6a33e58c9d9c49553Jean Chalard // We moved the cursor. If we are touching a word, we need to resume suggestion, 943aa3a96f3a1c5aeacefdfd6e6a33e58c9d9c49553Jean Chalard // unless suggestions are off. 944aa3a96f3a1c5aeacefdfd6e6a33e58c9d9c49553Jean Chalard if (isSuggestionsStripVisible()) { 945aa3a96f3a1c5aeacefdfd6e6a33e58c9d9c49553Jean Chalard mHandler.postResumeSuggestions(); 946aa3a96f3a1c5aeacefdfd6e6a33e58c9d9c49553Jean Chalard } 9471e5bbe4ce85db23528772d1b706149bb563c3ac7Jean Chalard // Reset the last recapitalization. 948b794e904a3586ac5f2d31fb24d5a1a8f9aa964b8Jean Chalard mRecapitalizeStatus.deactivate(); 949fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard mKeyboardSwitcher.updateShiftState(); 9504733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 9514733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = false; 952466741d8a78965b8509bf527344f289e50873092Mike LeBeau 953979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Make a note of the cursor position 954979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionStart = newSelStart; 955979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionEnd = newSelEnd; 9561931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mSubtypeState.currentSubtypeUsed(); 9577a8dac55278cedd838be325f56b4c52d973c61f5satok } 9587a8dac55278cedd838be325f56b4c52d973c61f5satok 959c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 960c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has clicked on the extracted text view, 961c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * when running in fullscreen mode. The default implementation hides 962913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * the suggestions view when this happens, but only if the extracted text 963c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * editor has a vertical scroll bar because its text doesn't fit. 964c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 965913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 966c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 967c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 968c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedTextClicked() { 969ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; 970c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 971c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedTextClicked(); 972c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 973c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 974c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 975c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has performed a cursor movement in the 976c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * extracted text view, when it is running in fullscreen mode. The default 977913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * implementation hides the suggestions view when a vertical movement 978c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * happens, but only if the extracted text editor has a vertical scroll bar 979c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * because its text doesn't fit. 980c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 981913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 982c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 983c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 984f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onExtractedCursorMovement(final int dx, final int dy) { 985ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) return; 986c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 987c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedCursorMovement(dx, dy); 988c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 989c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void hideWindow() { 992979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 993c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mKeyboardSwitcher.onHideWindow(); 994979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 995c2ee72a214fef46bc02ce486220365bbefd78714Alan Viverette if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) { 996c2ee72a214fef46bc02ce486220365bbefd78714Alan Viverette AccessibleKeyboardViewProxy.getInstance().onHideWindow(); 997c2ee72a214fef46bc02ce486220365bbefd78714Alan Viverette } 998c2ee72a214fef46bc02ce486220365bbefd78714Alan Viverette 999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (TRACE) Debug.stopMethodTracing(); 10006e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani if (mOptionsDialog != null && mOptionsDialog.isShowing()) { 10016e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog.dismiss(); 10026e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog = null; 10036e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 1004923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.hideWindow(); 1005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 1008f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onDisplayCompletions(final CompletionInfo[] applicationSpecifiedCompletions) { 1009979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG) { 1010a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa Log.i(TAG, "Received completions:"); 1011bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok if (applicationSpecifiedCompletions != null) { 1012bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 1013bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); 1014bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok } 1015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1017ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) return; 1018dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (applicationSpecifiedCompletions == null) { 1019259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 10209c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 102194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(null); 102294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 1023dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard return; 1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 10257be3ca2ccfe05f6659dbbac84de9ff1be4d92e3dJean Chalard mApplicationSpecifiedCompletions = 10267be3ca2ccfe05f6659dbbac84de9ff1be4d92e3dJean Chalard CompletionInfoUtils.removeNulls(applicationSpecifiedCompletions); 1027dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard 1028dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = 1029dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard SuggestedWords.getFromApplicationSpecifiedCompletions( 1030dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard applicationSpecifiedCompletions); 1031dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final SuggestedWords suggestedWords = new SuggestedWords( 1032dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard applicationSuggestedWords, 1033dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* typedWordValid */, 1034dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* hasAutoCorrectionCandidate */, 1035dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isPunctuationSuggestions */, 1036dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isObsoleteSuggestions */, 1037dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isPrediction */); 1038dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // When in fullscreen mode, show completions generated by the application 1039dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final boolean isAutoCorrection = false; 1040abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard setSuggestedWords(suggestedWords, isAutoCorrection); 1041dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard setAutoCorrectionIndicator(isAutoCorrection); 1042dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard setSuggestionStripShown(true); 10439c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 104494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); 104594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 1046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1047923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1048f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void setSuggestionStripShownInternal(final boolean shown, 1049f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final boolean needsInputViewShown) { 1050913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // TODO: Modify this if we support suggestions with hard keyboard 1051913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { 105227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 105327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final boolean inputViewShown = (mainKeyboardView != null) 105427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka ? mainKeyboardView.isShown() : false; 1055913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean shouldShowSuggestions = shown 1056433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka && (needsInputViewShown ? inputViewShown : true); 10574b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka if (isFullscreenMode()) { 1058913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 1059913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.GONE); 10607a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } else { 1061913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 1062913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); 10637a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } 1064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1066a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1067f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void setSuggestionStripShown(final boolean shown) { 1068c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); 1069543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa } 1070543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa 1071bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka private int getAdjustedBackingViewHeight() { 1072bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka final int currentHeight = mKeyPreviewBackingView.getHeight(); 1073bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka if (currentHeight > 0) { 1074bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return currentHeight; 1075c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 1076c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 1077f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 107827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView == null) { 1079bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return 0; 1080bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka } 108127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final int keyboardHeight = mainKeyboardView.getHeight(); 1082c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int suggestionsHeight = mSuggestionsContainer.getHeight(); 1083ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final int displayHeight = getResources().getDisplayMetrics().heightPixels; 1084c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final Rect rect = new Rect(); 1085c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); 1086c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int notificationBarHeight = rect.top; 1087c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight 1088c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka - keyboardHeight; 1089c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 1090c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final LayoutParams params = mKeyPreviewBackingView.getLayoutParams(); 10914702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka params.height = mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight); 1092c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.setLayoutParams(params); 1093bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return params.height; 1094c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 1095c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 1096543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa @Override 1097f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onComputeInsets(final InputMethodService.Insets outInsets) { 1098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onComputeInsets(outInsets); 1099f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 110027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView == null || mSuggestionsContainer == null) { 110146ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka return; 110227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 1103b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int adjustedBackingHeight = getAdjustedBackingViewHeight(); 1104b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); 1105b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int backingHeight = backingGone ? 0 : adjustedBackingHeight; 1106d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // In fullscreen mode, the height of the extract area managed by InputMethodService should 1107d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // be considered. 1108d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. 1109d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0; 111059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0 111159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka : mSuggestionsContainer.getHeight(); 1112d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extraHeight = extractHeight + backingHeight + suggestionsHeight; 1113fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang int visibleTopY = extraHeight; 11149e347d3d448e48229c46aad394ec9bd60cd5807bsatok // Need to set touchable region only if input view is being shown 111527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView.isShown()) { 1116913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { 1117fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang visibleTopY -= suggestionsHeight; 11189e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 1119fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang final int touchY = mainKeyboardView.isShowingMoreKeysPanel() ? 0 : visibleTopY; 112027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final int touchWidth = mainKeyboardView.getWidth(); 112127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final int touchHeight = mainKeyboardView.getHeight() + extraHeight 11227a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka // Extend touchable region below the keyboard. 11237a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + EXTENDED_TOUCHABLE_REGION_HEIGHT; 112413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; 112513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight); 11269e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 1127fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang outInsets.contentTopInsets = visibleTopY; 1128fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang outInsets.visibleTopInsets = visibleTopY; 1129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1130a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 1132979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean onEvaluateFullscreenMode() { 11339751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka // Reread resource value here, because this method is called by framework anytime as needed. 11349751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka final boolean isFullscreenModeAllowed = 1135d3b0ecec22cda883150851dced32c1eda2910a66Tadashi G. Takaoka Settings.readUseFullscreenMode(getResources()); 113660dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { 113760dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI 113860dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // implies NO_FULLSCREEN. However, the framework mistakenly does. i.e. NO_EXTRACT_UI 113960dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // without NO_FULLSCREEN doesn't work as expected. Because of this we need this 114060dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // hack for now. Let's get rid of this once the framework gets fixed. 114160dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka final EditorInfo ei = getCurrentInputEditorInfo(); 114260dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka return !(ei != null && ((ei.imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0)); 114360dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka } else { 114460dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka return false; 114560dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka } 114659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka } 114759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka 114859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka @Override 114959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka public void updateFullscreenMode() { 115059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka super.updateFullscreenMode(); 1151f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka 115259010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka if (mKeyPreviewBackingView == null) return; 1153549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka // In fullscreen mode, no need to have extra space to show the key preview. 115459010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka // If not, we should have extra space above the keyboard to show the key preview. 1155549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); 1156979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1157979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 11582649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // This will reset the whole input state to the starting state. It will clear 11594a5cb5c36a6a385ec0036981a0e93b0253e884b0Jean Chalard // the composing word, reset the last composed word, tell the inputconnection about it. 116028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard private void resetEntireInputState(final int newCursorPosition) { 11619f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard final boolean shouldFinishComposition = mWordComposer.isComposingWord(); 11622649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 1163ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().mBigramPredictionEnabled) { 1164ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard clearSuggestionStrip(); 1165ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard } else { 1166abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false); 1167ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard } 11689f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard mConnection.resetCachesUponCursorMove(newCursorPosition, shouldFinishComposition); 11692649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard } 11702649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard 11712692a8700737d8eed268039aa27b22a31669da08Jean Chalard private void resetComposingState(final boolean alsoResetLastComposedWord) { 11722692a8700737d8eed268039aa27b22a31669da08Jean Chalard mWordComposer.reset(); 11732692a8700737d8eed268039aa27b22a31669da08Jean Chalard if (alsoResetLastComposedWord) 11742692a8700737d8eed268039aa27b22a31669da08Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 11752692a8700737d8eed268039aa27b22a31669da08Jean Chalard } 11762692a8700737d8eed268039aa27b22a31669da08Jean Chalard 1177a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard private void commitTyped(final String separatorString) { 1178196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) return; 1179bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 11803651220327c051d8017045aa5e8919461507b3f8Jean Chalard if (typedWord.length() > 0) { 11819c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 11823b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.getInstance().onWordFinished(typedWord, mWordComposer.isBatchMode()); 1183f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge } 1184cb25e1fe3740122fd52921c41711f4204ad257fdKurt Partridge commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, 1185cb25e1fe3740122fd52921c41711f4204ad257fdKurt Partridge separatorString); 1186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1189a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from the KeyboardSwitcher which needs to know auto caps state to display 1190a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // the right layout. 1191553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka public int getCurrentAutoCapsState() { 1192ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (!mSettings.getCurrent().mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; 119303ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 119403ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final EditorInfo ei = getCurrentInputEditorInfo(); 1195553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; 119603ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final int inputType = ei.inputType; 119790a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Warning: this depends on mSpaceState, which may not be the most current value. If 119890a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // mSpaceState gets updated later, whoever called this may need to be told about it. 119990a91272447fd64bc54e06f08f45b11c45930767Jean Chalard return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale(), 120090a91272447fd64bc54e06f08f45b11c45930767Jean Chalard SPACE_STATE_PHANTOM == mSpaceState); 12011c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 12021c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 12038094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard public int getCurrentRecapitalizeState() { 12048094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard if (!mRecapitalizeStatus.isActive() 12058094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { 12068094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard // Not recapitalizing at the moment 12078094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard return RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; 12088094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard } 12098094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard return mRecapitalizeStatus.getCurrentMode(); 12108094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard } 12118094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard 1212adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // Factor in auto-caps and manual caps and compute the current caps mode. 1213adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard private int getActualCapsMode() { 12146686e63f2158eff07e39ff002ba211d0578f2a4fJean Chalard final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode(); 12156686e63f2158eff07e39ff002ba211d0578f2a4fJean Chalard if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; 1216adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard final int auto = getCurrentAutoCapsState(); 1217adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { 1218adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; 1219adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard } 1220adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard if (0 != auto) return WordComposer.CAPS_MODE_AUTO_SHIFTED; 1221adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return WordComposer.CAPS_MODE_OFF; 1222adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard } 1223adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard 1224bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard private void swapSwapperAndSpace() { 12253b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge final CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); 1226863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. 1227923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastTwo != null && lastTwo.length() == 2 1228240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastTwo.charAt(0) == Constants.CODE_SPACE) { 12295475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 1230f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge final String text = lastTwo.charAt(1) + " "; 1231f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge mConnection.commitText(text, 1); 12329c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 12333b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.latinIME_swapSwapperAndSpace(lastTwo, text); 1234d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1235b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 12364ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 12374ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 12384ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 12392b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private boolean maybeDoubleSpacePeriod() { 1240ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (!mSettings.getCurrent().mCorrectionEnabled) return false; 1241ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (!mSettings.getCurrent().mUseDoubleSpacePeriod) return false; 12422b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa if (!mHandler.isAcceptingDoubleSpacePeriod()) return false; 12435475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0); 1244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastThree != null && lastThree.length() == 3 12452b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa && canBeFollowedByDoubleSpacePeriod(lastThree.charAt(0)) 1246240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastThree.charAt(1) == Constants.CODE_SPACE 1247240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastThree.charAt(2) == Constants.CODE_SPACE) { 12482b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 12495475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 1250f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge final String textToInsert = ". "; 1251f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge mConnection.commitText(textToInsert, 1); 12529c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 12533b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, 12543b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge false /* isBatchMode */); 1255f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge } 1256b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1257120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 1258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1259120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return false; 1260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1261a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 12622b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private static boolean canBeFollowedByDoubleSpacePeriod(final int codePoint) { 1263344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: Check again whether there really ain't a better way to check this. 1264344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: This should probably be language-dependant... 1265344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka return Character.isLetterOrDigit(codePoint) 1266240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_SINGLE_QUOTE 1267240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_DOUBLE_QUOTE 1268240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_PARENTHESIS 1269240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_SQUARE_BRACKET 1270240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_CURLY_BRACKET 1271240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET; 1272344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka } 1273344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka 12744702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is 12754702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // pressed. 1276c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 127718d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard public void addWordToUserDictionary(final String word) { 127818d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard if (TextUtils.isEmpty(word)) { 127918d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // Probably never supposed to happen, but just in case. 128018d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard mPositionalInfoForUserDictPendingAddition = null; 128118d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard return; 128218d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard } 128396845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard final String wordToEdit; 1284ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka if (CapsModeUtils.isAutoCapsMode(mLastComposedWord.mCapitalizedMode)) { 128596845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard wordToEdit = word.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); 128696845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard } else { 128796845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard wordToEdit = word; 128896845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard } 128996845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard mUserDictionary.addWordToUserDictionary(wordToEdit); 129018d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard } 129118d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard 129218d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard public void onWordAddedToUserDictionary(final String newSpelling) { 129318d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // If word was added but not by us, bail out 129418d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard if (null == mPositionalInfoForUserDictPendingAddition) return; 129518d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard if (mWordComposer.isComposingWord()) { 129618d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard // We are late... give up and return 129718d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard mPositionalInfoForUserDictPendingAddition = null; 129818d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard return; 129918d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard } 130018d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard mPositionalInfoForUserDictPendingAddition.setActualWordBeingAdded(newSpelling); 130118d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard if (mPositionalInfoForUserDictPendingAddition.tryReplaceWithActualWord( 130296845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard mConnection, getCurrentInputEditorInfo(), mLastSelectionEnd, 130396845ecff62ac5a1131ce3eb8e6a06d3298dd984Jean Chalard mSubtypeSwitcher.getCurrentSubtypeLocale())) { 130418d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard mPositionalInfoForUserDictPendingAddition = null; 130518d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard } 1306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1308f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static boolean isAlphabet(final int code) { 13098fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka return Character.isLetter(code); 1310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1311a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1312e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka private void onSettingsKeyPressed() { 1313cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return; 1314911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa showSubtypeSelectorAndSettings(); 13159a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 13169a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1317cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa // Virtual codes representing custom requests. These are used in onCustomRequest() below. 1318cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; 1319cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa 1320cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa @Override 1321f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean onCustomRequest(final int requestCode) { 1322cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return false; 1323cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa switch (requestCode) { 1324cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa case CODE_SHOW_INPUT_METHOD_PICKER: 13256fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { 13266fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mRichImm.getInputMethodManager().showInputMethodPicker(); 1327cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return true; 13289a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1329cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 13309a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1331cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 13329a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 13339a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 13349a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok private boolean isShowingOptionDialog() { 13359a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok return mOptionsDialog != null && mOptionsDialog.isShowing(); 13369a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 13379a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1338f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void performEditorAction(final int actionId) { 13395475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.performEditorAction(actionId); 13407a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 13417a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 1342aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka // TODO: Revise the language switch key behavior to make it much smarter and more reasonable. 134381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private void handleLanguageSwitchKey() { 134481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final IBinder token = getWindow().getWindow().getAttributes().token; 1345ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList) { 13466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */); 1347aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka return; 1348aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka } 13491931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mSubtypeState.switchSubtype(token, mRichImm); 135081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 135181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka 135228d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard private void sendDownUpKeyEventForBackwardCompatibility(final int code) { 13534e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard final long eventTime = SystemClock.uptimeMillis(); 13545475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, 13554e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_DOWN, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 13564e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 13575475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, 13584e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_UP, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 13594e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 13604e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 13614e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard 1362f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void sendKeyCodePoint(final int code) { 13639c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 136499931201d0258ec93bd47de6f6f53ad59709bd85Kurt Partridge ResearchLogger.latinIME_sendKeyCodePoint(code); 136599931201d0258ec93bd47de6f6f53ad59709bd85Kurt Partridge } 13667a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // TODO: Remove this special handling of digit letters. 13677a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. 13687a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (code >= '0' && code <= '9') { 136928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard sendDownUpKeyEventForBackwardCompatibility(code - '0' + KeyEvent.KEYCODE_0); 13707a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return; 13717a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 13727a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 13737058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard if (Constants.CODE_ENTER == code && mAppWorkAroundsUtils.isBeforeJellyBean()) { 13745475b38328171a0841ae18074bd45380ec567e90Jean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 13755475b38328171a0841ae18074bd45380ec567e90Jean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 13765475b38328171a0841ae18074bd45380ec567e90Jean Chalard // reasons (there are race conditions with commits) but some applications are 13775475b38328171a0841ae18074bd45380ec567e90Jean Chalard // relying on this behavior so we continue to support it for older apps. 137828d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard sendDownUpKeyEventForBackwardCompatibility(KeyEvent.KEYCODE_ENTER); 13795475b38328171a0841ae18074bd45380ec567e90Jean Chalard } else { 13805475b38328171a0841ae18074bd45380ec567e90Jean Chalard final String text = new String(new int[] { code }, 0, 1); 13815475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, text.length()); 13825475b38328171a0841ae18074bd45380ec567e90Jean Chalard } 13837a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 13847a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 13855f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Implementation of {@link KeyboardActionListener}. 13865a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1387f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onCodeInput(final int primaryCode, final int x, final int y) { 13889c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 138999931201d0258ec93bd47de6f6f53ad59709bd85Kurt Partridge ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); 139099931201d0258ec93bd47de6f6f53ad59709bd85Kurt Partridge } 1391175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final long when = SystemClock.uptimeMillis(); 1392240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (primaryCode != Constants.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { 1393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDeleteCount = 0; 1394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1395923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mLastKeyTime = when; 1396f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 1397175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1398120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // The space state depends only on the last character pressed and its own previous 1399120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // state. Here, we revert the space state to neutral if the key is actually modifying 1400120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // the input contents (any non-shift key), which is what we should do for 1401120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // all inputs that do not result in a special state. Each character handling is then 1402120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // free to override the state as they see fit. 1403120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState = mSpaceState; 140470852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false; 1405ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 14062b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state. 1407240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (primaryCode != Constants.CODE_SPACE) { 14082b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 1409ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa } 1410ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1411c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1412923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 1413240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_DELETE: 1414120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1415120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleBackspace(spaceState); 14164189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka mDeleteCount++; 14174733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 1418140467b8b65eb9087a9b7f744dbb8a30481effe7Kurt Partridge LatinImeLogger.logOnDelete(x, y); 14194189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1420240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 14212995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // Note: calling back to the keyboard on Shift key is handled in onPressKey() 14222995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // and onReleaseKey(). 14231f523646303b935e3d5031e75a4c74f4ecd96b97Jean Chalard final Keyboard currentKeyboard = switcher.getKeyboard(); 14241f523646303b935e3d5031e75a4c74f4ecd96b97Jean Chalard if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) { 14251f523646303b935e3d5031e75a4c74f4ecd96b97Jean Chalard // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for 14261f523646303b935e3d5031e75a4c74f4ecd96b97Jean Chalard // alphabetic shift and shift while in symbol layout. 14271f523646303b935e3d5031e75a4c74f4ecd96b97Jean Chalard handleRecapitalize(); 14281f523646303b935e3d5031e75a4c74f4ecd96b97Jean Chalard } 14292995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard break; 1430240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SWITCH_ALPHA_SYMBOL: 14312995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // Note: calling back to the keyboard on symbol key is handled in onPressKey() 14322995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // and onReleaseKey(). 14334189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1434240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SETTINGS: 143593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka onSettingsKeyPressed(); 14364189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1437240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHORTCUT: 14389fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka mSubtypeSwitcher.switchToShortcutIME(this); 14394189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1440240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_ACTION_NEXT: 14418f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_NEXT); 144205bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka break; 1443240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_ACTION_PREVIOUS: 14448f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); 14454189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1446240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_LANGUAGE_SWITCH: 144781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka handleLanguageSwitchKey(); 144881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka break; 1449240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_RESEARCH: 14509c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 145158eb4d9f27595202927150766d198a0bff15efadKurt Partridge ResearchLogger.getInstance().onResearchKeySelected(this); 1452724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge } 1453724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge break; 14544e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard case Constants.CODE_ENTER: 14554e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard final EditorInfo editorInfo = getCurrentInputEditorInfo(); 14564e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard final int imeOptionsActionId = 14574e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard InputTypeUtils.getImeOptionsActionIdFromEditorInfo(editorInfo); 14584e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard if (InputTypeUtils.IME_ACTION_CUSTOM_LABEL == imeOptionsActionId) { 14594e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // Either we have an actionLabel and we should performEditorAction with actionId 14604e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // regardless of its value. 14614e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard performEditorAction(editorInfo.actionId); 14624e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard } else if (EditorInfo.IME_ACTION_NONE != imeOptionsActionId) { 14634e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // We didn't have an actionLabel, but we had another action to execute. 14644e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // EditorInfo.IME_ACTION_NONE explicitly means no action. In contrast, 14654e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // EditorInfo.IME_ACTION_UNSPECIFIED is the default value for an action, so it 14664e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // means there should be an action and the app didn't bother to set a specific 14674e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // code for it - presumably it only handles one. It does not have to be treated 14684e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // in any specific way: anything that is not IME_ACTION_NONE should be sent to 14694e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // performEditorAction. 14704e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard performEditorAction(imeOptionsActionId); 14714e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard } else { 14724e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // No action label, and the action from imeOptions is NONE: this is a regular 14734e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard // enter key that should input a carriage return. 14744e4f88127b6a75302fac3a004e41fff1899a773fJean Chalard didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState); 14754189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 1476dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard break; 1477dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard case Constants.CODE_SHIFT_ENTER: 1478dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard didAutoCorrect = handleNonSpecialCharacter(Constants.CODE_ENTER, x, y, spaceState); 1479dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard break; 1480dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard default: 1481dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard didAutoCorrect = handleNonSpecialCharacter(primaryCode, x, y, spaceState); 14824733609947c0ec74e460bd714fffca0518ade93aJean Chalard break; 1483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1484eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka switcher.onCodeInput(primaryCode); 1485125de3dfdf548359de890247907f2e6f430008ecJean Chalard // Reset after any single keystroke, except shift and symbol-shift 1486240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (!didAutoCorrect && primaryCode != Constants.CODE_SHIFT 1487240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && primaryCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) 1488c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard mLastComposedWord.deactivate(); 1489240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_DELETE != primaryCode) { 1490a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mEnteredText = null; 1491a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard } 1492e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard mConnection.endBatchEdit(); 1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1494a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1495dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard private boolean handleNonSpecialCharacter(final int primaryCode, final int x, final int y, 1496dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard final int spaceState) { 1497dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard mSpaceState = SPACE_STATE_NONE; 1498dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard final boolean didAutoCorrect; 1499dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard if (mSettings.getCurrent().isWordSeparator(primaryCode)) { 1500dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); 1501dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } else { 1502dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard didAutoCorrect = false; 1503dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard if (SPACE_STATE_PHANTOM == spaceState) { 1504756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 1505dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) { 1506dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard Stats.onAutoCorrection( 1507dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard "", mWordComposer.getTypedWord(), " ", mWordComposer); 1508dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } 1509dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } 15100e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { 15110e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // If we are in the middle of a recorrection, we need to commit the recorrection 15120e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // first so that we can insert the character at the current cursor position. 15130e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard resetEntireInputState(mLastSelectionStart); 15140e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } else { 15150e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 15160e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 1517dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } 1518dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard final int keyX, keyY; 1519dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 1520dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { 1521dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard keyX = x; 1522dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard keyY = y; 1523dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } else { 1524dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard keyX = Constants.NOT_A_COORDINATE; 1525dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard keyY = Constants.NOT_A_COORDINATE; 1526dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } 1527dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard handleCharacter(primaryCode, keyX, keyY, spaceState); 1528dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } 1529dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard mExpectingUpdateSelection = true; 1530dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard return didAutoCorrect; 1531dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard } 1532dcfceaff1b18b102d7fe875b48b84c24cbd822d9Jean Chalard 1533a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from PointerTracker through the KeyboardActionListener interface 15345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1535bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void onTextInput(final String rawText) { 1536f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 15376c70b9200340537d05ff8932d7cd990269eb486dJean Chalard if (mWordComposer.isComposingWord()) { 15384aff3bf0eaf4aec38c1d8576fdfc85a9eaa1c544Kurt Partridge commitCurrentAutoCorrection(rawText); 1539a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard } else { 1540a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 15416c70b9200340537d05ff8932d7cd990269eb486dJean Chalard } 15420a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka mHandler.postUpdateSuggestionStrip(); 1543bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String text = specificTldProcessingOnTextInput(rawText); 1544fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == mSpaceState) { 15450e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 1546fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 15475475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, 1); 15489c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 15493b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.latinIME_onTextInput(text, false /* isBatchMode */); 1550f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge } 15515475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 155290a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Space state must be updated before calling updateShiftState 155390a91272447fd64bc54e06f08f45b11c45930767Jean Chalard mSpaceState = SPACE_STATE_NONE; 1554b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1555240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT); 1556dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = text; 1557923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1558923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 15594be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 15604be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka public void onStartBatchInput() { 1561f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka BatchInputUpdater.getInstance().onStartBatchInput(this); 1562a280e56014dd15321ecc96a65f18dbd0c0b210f6Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 15634be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.beginBatchEdit(); 15644be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (mWordComposer.isComposingWord()) { 1565756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 156687cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (mWordComposer.isBatchMode()) { 156787cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); 156887cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 156987cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 1570e3ec5fcc88513a4141577e5b2001b3896e111232Jean Chalard final int wordComposerSize = mWordComposer.size(); 1571e3ec5fcc88513a4141577e5b2001b3896e111232Jean Chalard // Since isComposingWord() is true, the size is at least 1. 15720e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard final int lastChar = mWordComposer.getCodeBeforeCursor(); 15730e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { 15740e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // If we are in the middle of a recorrection, we need to commit the recorrection 15750e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // first so that we can insert the batch input at the current cursor position. 15760e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard resetEntireInputState(mLastSelectionStart); 15770e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } else if (wordComposerSize <= 1) { 1578b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // We auto-correct the previous (typed, not gestured) string iff it's one character 1579b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // long. The reason for this is, even in the middle of gesture typing, you'll still 1580b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // tap one-letter words and you want them auto-corrected (typically, "i" in English 1581b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // should become "I"). However for any longer word, we assume that the reason for 1582b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // tapping probably is that the word you intend to type is not in the dictionary, 1583b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // so we do not attempt to correct, on the assumption that if that was a dictionary 1584b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // word, the user would probably have gestured instead. 1585b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard commitCurrentAutoCorrection(LastComposedWord.NOT_A_SEPARATOR); 1586b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard } else { 1587b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 1588b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard } 15894be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mExpectingUpdateSelection = true; 1590e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard } 1591e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); 1592e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard if (Character.isLetterOrDigit(codePointBeforeCursor) 1593e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard || mSettings.getCurrent().isUsuallyFollowedBySpace(codePointBeforeCursor)) { 1594e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard mSpaceState = SPACE_STATE_PHANTOM; 15954be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 15964be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.endBatchEdit(); 1597adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); 1598eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1599eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 1600f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final class BatchInputUpdater implements Handler.Callback { 1601f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private final Handler mHandler; 1602f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private LatinIME mLatinIme; 1603ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka private final Object mLock = new Object(); 1604ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka private boolean mInBatchInput; // synchronized using {@link #mLock}. 1605f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1606f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private BatchInputUpdater() { 1607f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final HandlerThread handlerThread = new HandlerThread( 1608f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka BatchInputUpdater.class.getSimpleName()); 1609f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka handlerThread.start(); 1610f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mHandler = new Handler(handlerThread.getLooper(), this); 1611f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1612f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1613f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka // Initialization-on-demand holder 1614f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final class OnDemandInitializationHolder { 1615f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public static final BatchInputUpdater sInstance = new BatchInputUpdater(); 1616f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1617f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1618f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public static BatchInputUpdater getInstance() { 1619f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return OnDemandInitializationHolder.sInstance; 1620f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1621f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1622f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final int MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 1; 1623f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1624f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka @Override 1625f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean handleMessage(final Message msg) { 1626f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka switch (msg.what) { 1627f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: 1628f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka updateBatchInput((InputPointers)msg.obj); 1629f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka break; 1630f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1631f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return true; 1632f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1633f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 163458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the UI thread. 1635ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka public void onStartBatchInput(final LatinIME latinIme) { 1636ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka synchronized (mLock) { 1637ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); 1638ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mLatinIme = latinIme; 1639ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mInBatchInput = true; 1640ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka } 164158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 164258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 164358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the Handler thread. 1644ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka private void updateBatchInput(final InputPointers batchPointers) { 1645ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka synchronized (mLock) { 1646ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka if (!mInBatchInput) { 1647ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka // Batch input has ended or canceled while the message was being delivered. 1648ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka return; 1649ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka } 1650ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(batchPointers); 1651ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( 1652ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka suggestedWords, false /* dismissGestureFloatingPreviewText */); 165358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 165458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 165558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 165658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the UI thread. 1657f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka public void onUpdateBatchInput(final InputPointers batchPointers) { 1658f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) { 1659f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return; 1660f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1661f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mHandler.obtainMessage( 1662f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, batchPointers) 1663f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka .sendToTarget(); 1664f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1665f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1666ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka public void onCancelBatchInput() { 1667ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka synchronized (mLock) { 1668ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mInBatchInput = false; 1669ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( 1670ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); 1671ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka } 1672b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1673b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 167458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the UI thread. 1675ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka public SuggestedWords onEndBatchInput(final InputPointers batchPointers) { 1676ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka synchronized (mLock) { 1677ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mInBatchInput = false; 1678ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked(batchPointers); 1679ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka mLatinIme.mHandler.showGesturePreviewAndSuggestionStrip( 1680ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka suggestedWords, true /* dismissGestureFloatingPreviewText */); 1681ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka return suggestedWords; 1682ce811f50d2cfa1cb5586d60943cfc10a28dffcccTadashi G. Takaoka } 1683f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1684f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1685f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka // {@link LatinIME#getSuggestedWords(int)} method calls with same session id have to 1686f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka // be synchronized. 1687f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka private SuggestedWords getSuggestedWordsGestureLocked(final InputPointers batchPointers) { 1688f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka mLatinIme.mWordComposer.setBatchInputPointers(batchPointers); 1689f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka final SuggestedWords suggestedWords = 1690ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard mLatinIme.getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_GESTURE); 1691f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka final int suggestionCount = suggestedWords.size(); 1692f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka if (suggestionCount <= 1) { 1693f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka final String mostProbableSuggestion = (suggestionCount == 0) ? null 1694f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka : suggestedWords.getWord(0); 1695f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka return mLatinIme.getOlderSuggestions(mostProbableSuggestion); 1696f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka } 1697f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka return suggestedWords; 1698f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1699f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1700f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1701f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, 1702f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final boolean dismissGestureFloatingPreviewText) { 1703f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka showSuggestionStrip(suggestedWords, null); 1704375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 170550d902ac6fd018131bd7044dd968bb99e0fdba7bTadashi G. Takaoka mainKeyboardView.showGestureFloatingPreviewText(suggestedWords); 1706f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka if (dismissGestureFloatingPreviewText) { 1707f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mainKeyboardView.dismissGestureFloatingPreviewText(); 1708f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 17094be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 17104be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 17114be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 1712f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onUpdateBatchInput(final InputPointers batchPointers) { 1713f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka BatchInputUpdater.getInstance().onUpdateBatchInput(batchPointers); 1714f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1715f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1716f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka @Override 1717f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onEndBatchInput(final InputPointers batchPointers) { 171858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final SuggestedWords suggestedWords = BatchInputUpdater.getInstance().onEndBatchInput( 1719f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka batchPointers); 1720c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka final String batchInputText = suggestedWords.isEmpty() 1721c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka ? null : suggestedWords.getWord(0); 1722f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka if (TextUtils.isEmpty(batchInputText)) { 172310102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka return; 172410102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka } 1725f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mWordComposer.setBatchInputWord(batchInputText); 17264be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.beginBatchEdit(); 17274be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (SPACE_STATE_PHANTOM == mSpaceState) { 17280e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 17294be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 1730f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mConnection.setComposingText(batchInputText, 1); 17314be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mExpectingUpdateSelection = true; 17324be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.endBatchEdit(); 17339c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 17340c16a5c6eef645fd536671994e0b4f05864ac338Kurt Partridge ResearchLogger.latinIME_onEndBatchInput(batchInputText, 0, suggestedWords); 173548160f9d847c0246883bc81599613b1ebe2652a6Kurt Partridge } 173690a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Space state must be updated before calling updateShiftState 17374be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mSpaceState = SPACE_STATE_PHANTOM; 173890a91272447fd64bc54e06f08f45b11c45930767Jean Chalard mKeyboardSwitcher.updateShiftState(); 17394be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 17404be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 1741bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String specificTldProcessingOnTextInput(final String text) { 1742240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (text.length() <= 1 || text.charAt(0) != Constants.CODE_PERIOD 1743fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard || !Character.isLetter(text.charAt(1))) { 1744fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Not a tld: do nothing. 1745fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1746fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 174712d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // We have a TLD (or something that looks like this): make sure we don't add 174812d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // a space even if currently in phantom mode. 174912d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard mSpaceState = SPACE_STATE_NONE; 1750e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard // TODO: use getCodePointBeforeCursor instead to improve performance and simplify the code 17515475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0); 1752fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (lastOne != null && lastOne.length() == 1 1753240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastOne.charAt(0) == Constants.CODE_PERIOD) { 1754bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka return text.substring(1); 1755fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else { 1756fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1757fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1758fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1759fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1760a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from PointerTracker through the KeyboardActionListener interface 17615a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 176241016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka public void onFinishSlidingInput() { 176341016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka // User finished sliding input. 176441016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka mKeyboardSwitcher.onFinishSlidingInput(); 176541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka } 176641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka 176741016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka // Called from PointerTracker through the KeyboardActionListener interface 176841016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka @Override 17698aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() { 177083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka // User released a finger outside any key 177141016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka // Nothing to do so far. 177283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } 177383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka 1774b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka @Override 1775b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public void onCancelBatchInput() { 1776f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka BatchInputUpdater.getInstance().onCancelBatchInput(); 1777b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1778b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 1779120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleBackspace(final int spaceState) { 1780fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // In many cases, we may have to put the keyboard in auto-shift state again. However 1781fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // we want to wait a few milliseconds before doing it to avoid the keyboard flashing 1782fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // during key repeat. 1783beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 17842245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard 17850e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { 17860e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // If we are in the middle of a recorrection, we need to commit the recorrection 17870e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // first so that we can remove the character at the current cursor position. 17886a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard resetEntireInputState(mLastSelectionStart); 17890e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // When we exit this if-clause, mWordComposer.isComposingWord() will return false. 17906a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 1791196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 17923651220327c051d8017045aa5e8919461507b3f8Jean Chalard final int length = mWordComposer.size(); 1793923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (length > 0) { 179401d47b809617aee03e240a6b4b41013269547bc1Jean Chalard if (mWordComposer.isBatchMode()) { 17959c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 17963b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge final String word = mWordComposer.getTypedWord(); 1797ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge ResearchLogger.latinIME_handleBackspace_batch(word, 1); 17983b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.getInstance().uncommitCurrentLogUnit( 17993b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge word, false /* dumpCurrentLogUnit */); 1800f1ce54891f54b4b75a7662fe08204e9d50e54e55Kurt Partridge } 1801d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard final String rejectedSuggestion = mWordComposer.getTypedWord(); 18023b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge mWordComposer.reset(); 1803d40f3f6bc1bcf07800fbee0468fe90d307ca28bbJean Chalard mWordComposer.setRejectedBatchModeSuggestion(rejectedSuggestion); 18044be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } else { 18054be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mWordComposer.deleteLast(); 18064be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 18075475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1808a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 1809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 18105475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1811923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1812890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } else { 18135935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard if (mLastComposedWord.canRevertCommit()) { 1814756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 181587cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onAutoCorrectionCancellation(); 181687cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 18175475b38328171a0841ae18074bd45380ec567e90Jean Chalard revertCommit(); 1818120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return; 1819120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1820a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) { 1821a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // Cancel multi-character input: remove the text we just entered. 1822a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // This is triggered on backspace after a key that inputs multiple characters, 1823a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // like the smiley key or the .com key. 1824a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard final int length = mEnteredText.length(); 1825a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mConnection.deleteSurroundingText(length, 0); 1826a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mEnteredText = null; 1827a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. 1828a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // In addition we know that spaceState is false, and that we should not be 1829a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // reverting any autocorrect at this point. So we can safely return. 1830a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard return; 1831a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard } 1832d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (SPACE_STATE_DOUBLE == spaceState) { 18332b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 183499f31896454eff3789e00949dcce83f6914fe3f4Kurt Partridge if (mConnection.revertDoubleSpacePeriod()) { 1835d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // No need to reset mSpaceState, it has already be done (that's why we 1836d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // receive it as a parameter) 1837d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1838d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 1839d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 18402010aad741bc1a7266913bcb8b8348d6e401c95bJean Chalard if (mConnection.revertSwapPunctuation()) { 1841d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // Likewise 1842d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1843d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 18444733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 1845504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka 18464fef31510df542a3324426a6750950194d016086Jean Chalard // No cancelling of commit/double space/swap: we have a regular backspace. 18474fef31510df542a3324426a6750950194d016086Jean Chalard // We should backspace one char and restart suggestion if at the end of a word. 18484fef31510df542a3324426a6750950194d016086Jean Chalard if (mLastSelectionStart != mLastSelectionEnd) { 18494fef31510df542a3324426a6750950194d016086Jean Chalard // If there is a selection, remove it. 1850ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; 18515475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); 1852516b63db2866f144a00ec7e1e6c29cb0865f5ff3Jean Chalard // Reset mLastSelectionEnd to mLastSelectionStart. This is what is supposed to 1853516b63db2866f144a00ec7e1e6c29cb0865f5ff3Jean Chalard // happen, and if it's wrong, the next call to onUpdateSelection will correct it, 1854516b63db2866f144a00ec7e1e6c29cb0865f5ff3Jean Chalard // but we want to set it right away to avoid it being used with the wrong values 1855516b63db2866f144a00ec7e1e6c29cb0865f5ff3Jean Chalard // later (typically, in a subsequent press on backspace). 1856516b63db2866f144a00ec7e1e6c29cb0865f5ff3Jean Chalard mLastSelectionEnd = mLastSelectionStart; 1857ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge mConnection.deleteSurroundingText(numCharsDeleted, 0); 18589c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 1859ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge ResearchLogger.latinIME_handleBackspace(numCharsDeleted); 1860ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge } 18616558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } else { 18624fef31510df542a3324426a6750950194d016086Jean Chalard // There is no selection, just delete one character. 18634fef31510df542a3324426a6750950194d016086Jean Chalard if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { 18644fef31510df542a3324426a6750950194d016086Jean Chalard // This should never happen. 18654fef31510df542a3324426a6750950194d016086Jean Chalard Log.e(TAG, "Backspace when we don't know the selection position"); 18666558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 18677058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard if (mAppWorkAroundsUtils.isBeforeJellyBean()) { 18684e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 18694e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 18704e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // reasons (there are race conditions with commits) but some applications are 18714e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // relying on this behavior so we continue to support it for older apps. 187228d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard sendDownUpKeyEventForBackwardCompatibility(KeyEvent.KEYCODE_DEL); 18734e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } else { 18745475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 18754e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 18769c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 1877ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge ResearchLogger.latinIME_handleBackspace(1); 1878ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge } 18794fef31510df542a3324426a6750950194d016086Jean Chalard if (mDeleteCount > DELETE_ACCELERATE_AT) { 18805475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 18819c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 1882ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge ResearchLogger.latinIME_handleBackspace(1); 1883ef3936bc5470360144c3efc4dab9ef24a57c1e34Kurt Partridge } 1884edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1886ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { 18875475b38328171a0841ae18074bd45380ec567e90Jean Chalard restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); 18884fef31510df542a3324426a6750950194d016086Jean Chalard } 1889923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1890923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1891923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1892ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard /* 1893ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard * Strip a trailing space if necessary and returns whether it's a swap weak space situation. 1894ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard */ 1895e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard private boolean maybeStripSpace(final int code, 1896e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final int spaceState, final boolean isFromSuggestionStrip) { 1897240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1898bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1899e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1900ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard } 1901ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState) 1902e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard && isFromSuggestionStrip) { 1903ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard if (mSettings.getCurrent().isUsuallyPrecededBySpace(code)) return false; 1904ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard if (mSettings.getCurrent().isUsuallyFollowedBySpace(code)) return true; 1905ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard mConnection.removeTrailingSpace(); 1906e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1907ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard return false; 1908e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1909e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1910ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void handleCharacter(final int primaryCode, final int x, 1911120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int y, final int spaceState) { 1912196d82cdd740580ed79d801483dbc282be85d076Jean Chalard boolean isComposingWord = mWordComposer.isComposingWord(); 1913fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1914e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. 1915e8b9b3547145c5f706eede949e6c1c1ddcc9f857Jean Chalard // See onStartBatchInput() to see how to do it. 1916fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1917ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard !mSettings.getCurrent().isWordConnector(primaryCode)) { 1918fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (isComposingWord) { 1919fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Sanity check 1920fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard throw new RuntimeException("Should not be composing here"); 1921fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 19220e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 1923fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1924fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 19250e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { 19260e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // If we are in the middle of a recorrection, we need to commit the recorrection 19270e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // first so that we can insert the character at the current cursor position. 19286a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard resetEntireInputState(mLastSelectionStart); 19296a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard isComposingWord = false; 19306a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 1931d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several 1932d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI 1933d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // thread here. 1934d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard if (!isComposingWord && (isAlphabet(primaryCode) 1935ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard || mSettings.getCurrent().isWordConnector(primaryCode)) 1936ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka && mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation) && 1937ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka !mConnection.isCursorTouchingWord(mSettings.getCurrent())) { 1938736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Reset entirely the composing state anyway, then start composing a new word unless 1939736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // the character is a single quote. The idea here is, single quote is not a 1940736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // separator and it should be treated as a normal character, except in the first 1941736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // position where it should not start composing a word. 1942240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode); 1943736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Here we don't need to reset the last composed word. It will be reset 1944736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // when we commit this one, if we ever do; if on the other hand we backspace 1945736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // it entirely and resume suggestions on the previous word, we'd like to still 1946736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // have touch coordinates for it. 1947736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard resetComposingState(false /* alsoResetLastComposedWord */); 1948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 19497b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (isComposingWord) { 19505c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka final int keyX, keyY; 195124ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka if (Constants.isValidCoordinate(x) && Constants.isValidCoordinate(y)) { 19525c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka final KeyDetector keyDetector = 195327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mKeyboardSwitcher.getMainKeyboardView().getKeyDetector(); 19545c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyX = keyDetector.getTouchX(x); 19555c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyY = keyDetector.getTouchY(y); 195624ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka } else { 195724ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka keyX = x; 195824ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka keyY = y; 19595c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka } 19605c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka mWordComposer.add(primaryCode, keyX, keyY); 19615475b38328171a0841ae18074bd45380ec567e90Jean Chalard // If it's the first letter, make note of auto-caps state 19625475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (mWordComposer.size() == 1) { 1963adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); 1964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 19655475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1967e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, 1968ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x); 1969863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 19707a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 1971e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1972e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (swapWeakSpace) { 1973bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 1974e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard mSpaceState = SPACE_STATE_WEAK; 1975e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 19768f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // In case the "add to dictionary" hint was still displayed. 19774702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint(); 1978e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1979a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 1980756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 198187cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Utils.Stats.onNonSeparator((char)primaryCode, x, y); 198287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 1983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19852995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard private void handleRecapitalize() { 19862995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard if (mLastSelectionStart == mLastSelectionEnd) return; // No selection 19872995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // If we have a recapitalize in progress, use it; otherwise, create a new one. 1988b794e904a3586ac5f2d31fb24d5a1a8f9aa964b8Jean Chalard if (!mRecapitalizeStatus.isActive() 19892995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { 19903bdf341ea001cef70da803749e17484d19a9726aJean Chalard final CharSequence selectedText = 19913bdf341ea001cef70da803749e17484d19a9726aJean Chalard mConnection.getSelectedText(0 /* flags, 0 for no styles */); 19923bdf341ea001cef70da803749e17484d19a9726aJean Chalard if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection 1993b794e904a3586ac5f2d31fb24d5a1a8f9aa964b8Jean Chalard mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd, 19943bdf341ea001cef70da803749e17484d19a9726aJean Chalard selectedText.toString(), mSettings.getCurrentLocale(), 19953bdf341ea001cef70da803749e17484d19a9726aJean Chalard mSettings.getWordSeparators()); 19962995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // We trim leading and trailing whitespace. 19972995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mRecapitalizeStatus.trim(); 19982995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // Trimming the object may have changed the length of the string, and we need to 19992995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // reposition the selection handles accordingly. As this result in an IPC call, 20002995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // only do it if it's actually necessary, in other words if the recapitalize status 20012995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard // is not set at the same place as before. 20022995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { 20032995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); 20042995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); 20052995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); 20062995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard } 20072995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard } 20082995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mRecapitalizeStatus.rotate(); 20092995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; 20102995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); 20112995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mConnection.deleteSurroundingText(numCharsDeleted, 0); 20122995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); 20132995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); 20142995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); 20152995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); 20168094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard // Match the keyboard to the new state. 20178094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard mKeyboardSwitcher.updateShiftState(); 20182995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard } 20192995abe7aadd483aa57a9b088740d46ac07bbe46Jean Chalard 2020c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard // Returns true if we did an autocorrection, false otherwise. 2021c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard private boolean handleSeparator(final int primaryCode, final int x, final int y, 2022120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState) { 20239c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 202480375649d36c3e3aeec3a266827bb2d66d95d0f7Kurt Partridge ResearchLogger.latinIME_handleSeparator(primaryCode, mWordComposer.isComposingWord()); 202590aaa2d0a59227e948aefc5fbc4c875dae006ccfKurt Partridge } 2026c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 20270e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { 20280e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // If we are in the middle of a recorrection, we need to commit the recorrection 20290e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // first so that we can insert the separator at the current cursor position. 20300e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard resetEntireInputState(mLastSelectionStart); 20310e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 2032196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 2033ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().mCorrectionEnabled) { 2034a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // TODO: maybe cache Strings in an <String> sparse array or something 2035a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1)); 2036c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = true; 2037923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 2038a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard commitTyped(new String(new int[]{primaryCode}, 0, 1)); 2039923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 20414ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 2042e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, spaceState, 2043ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka Constants.SUGGESTION_STRIP_COORDINATE == x); 2044863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 204500ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard if (SPACE_STATE_PHANTOM == spaceState && 2046ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard mSettings.getCurrent().isUsuallyPrecededBySpace(primaryCode)) { 20470e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 204800ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard } 20497a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 205089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 2051240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_SPACE == primaryCode) { 2052ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { 20532b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa if (maybeDoubleSpacePeriod()) { 2054120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_DOUBLE; 2055120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else if (!isShowingPunctuationList()) { 2056120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_WEAK; 2057120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 2058126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 2059120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 20602b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.startDoubleSpacePeriodTimer(); 2061ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard mHandler.postUpdateSuggestionStrip(); 206289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 2063fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (swapWeakSpace) { 2064bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 20654721427c7de3600f6fe7dfff16508a6a974fb3e4Jean Chalard mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; 2066f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard } else if (SPACE_STATE_PHANTOM == spaceState 2067ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard && mSettings.getCurrent().isUsuallyFollowedBySpace(primaryCode)) { 2068fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // If we are in phantom space state, and the user presses a separator, we want to 2069fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // stay in phantom space state so that the next keypress has a chance to add the 2070fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // space. For example, if I type "Good dat", pick "day" from the suggestion strip 2071fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // then insert a comma and go on to typing the next word, I want the space to be 2072fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // inserted automatically before the next word, the same way it is when I don't 2073fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // input the comma. 2074f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // The case is a little different if the separator is a space stripper. Such a 2075f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // separator does not normally need a space on the right (that's the difference 2076f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // between swappers and strippers), so we should not stay in phantom space state if 2077f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // the separator is a stripper. Hence the additional test above. 2078fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 2079120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 2080120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 208189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Set punctuation right away. onUpdateSelection will fire but tests whether it is 208289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // already displayed or not, so it's okay. 208355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka setPunctuationSuggestions(); 2084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2085756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 208687cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Utils.Stats.onSeparator((char)primaryCode, x, y); 208787cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 2088120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 2089fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard mKeyboardSwitcher.updateShiftState(); 2090c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard return didAutoCorrect; 2091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2092466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2093bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private CharSequence getTextWithUnderline(final String text) { 20940a59ac2ba88ac1f99151d9336136bc6fe7d416c0Jean Chalard return mIsAutoCorrectionIndicatorOn 209577d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) 2096fda847a870829f1491cbd5325f9c985213081149Jean Chalard : text; 209777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 209877d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard 2099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void handleClose() { 2100f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge // TODO: Verify that words are logged properly when IME is closed. 21015475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 2102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestHideSelf(0); 210327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 210427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 210527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 21060a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka } 2107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2109a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // TODO: make this private 2110a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Outside LatinIME, only used by the test suite. 211115f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting 21129fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka boolean isShowingPunctuationList() { 2113abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard if (mSuggestedWords == null) return false; 2114abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard return mSettings.getCurrent().mSuggestPuncList == mSuggestedWords; 21157599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 21167599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 2117a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private boolean isSuggestionsStripVisible() { 21183efa36f6aab4d3fd970f87a72805e647213105ebKen Wakasa if (mSuggestionStripView == null) 2119b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa return false; 21203efa36f6aab4d3fd970f87a72805e647213105ebKen Wakasa if (mSuggestionStripView.isShowingAddToDictionaryHint()) 21219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 21223efa36f6aab4d3fd970f87a72805e647213105ebKen Wakasa if (null == mSettings.getCurrent()) 2123aa3a96f3a1c5aeacefdfd6e6a33e58c9d9c49553Jean Chalard return false; 21243efa36f6aab4d3fd970f87a72805e647213105ebKen Wakasa if (!mSettings.getCurrent().isSuggestionStripVisibleInOrientation(mDisplayOrientation)) 21259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return false; 21263efa36f6aab4d3fd970f87a72805e647213105ebKen Wakasa if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) 21279fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 2128ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka return mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation); 2129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2131259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka private void clearSuggestionStrip() { 2132abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard setSuggestedWords(SuggestedWords.EMPTY, false); 21337204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 2134466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2135466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2136abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard private void setSuggestedWords(final SuggestedWords words, final boolean isAutoCorrection) { 2137abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard mSuggestedWords = words; 21384702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) { 21394702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.setSuggestions(words); 2140dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection); 2141466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2142d02783cb63293507e8544ea60d07559092ce83d4Jean Chalard } 2143ec780e2868962bf17f0dfd35d36895f543bde40asatok 214438e535e59676ac4d7bf27026fe3e16fcd9eb292eJean Chalard private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { 2145ec780e2868962bf17f0dfd35d36895f543bde40asatok // Put a blue underline to a word in TextView which will be auto-corrected. 21462be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator 21472be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard && mWordComposer.isComposingWord()) { 21482be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; 21492be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard final CharSequence textWithUnderline = 21502be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard getTextWithUnderline(mWordComposer.getTypedWord()); 2151574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // TODO: when called from an updateSuggestionStrip() call that results from a posted 2152574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // message, this is called outside any batch edit. Potentially, this may result in some 2153574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // janky flickering of the screen, although the display speed makes it unlikely in 2154574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // the practice. 21555475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(textWithUnderline, 1); 2156ec780e2868962bf17f0dfd35d36895f543bde40asatok } 2157466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2158466741d8a78965b8509bf527344f289e50873092Mike LeBeau 21597575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka private void updateSuggestionStrip() { 2160d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 2161305326e789c3a89517855cc5a023ed1aa3074dc0Jean Chalard 2162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Check if we have a suggestion engine attached. 2163ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSuggest == null 2164ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka || !mSettings.getCurrent().isSuggestionsRequested(mDisplayOrientation)) { 2165edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard if (mWordComposer.isComposingWord()) { 21667ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " 21677ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard + "requested!"); 2168edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 21697575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return; 2170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2171466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2172ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (!mWordComposer.isComposingWord() && !mSettings.getCurrent().mBigramPredictionEnabled) { 2173e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard setPunctuationSuggestions(); 21747575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return; 2175e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard } 2176e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard 2177ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard final SuggestedWords suggestedWords = 2178ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard getSuggestedWordsOrOlderSuggestions(Suggest.SESSION_TYPING); 21797575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 21807575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka showSuggestionStrip(suggestedWords, typedWord); 21817575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka } 21827575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka 2183f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private SuggestedWords getSuggestedWords(final int sessionId) { 2184d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2185c7318bbc0b47662799d2f7a01e5b53edb43ebf2aTadashi G. Takaoka if (keyboard == null || mSuggest == null) { 2186d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka return SuggestedWords.EMPTY; 2187d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka } 218832f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // Get the word on which we should search the bigrams. If we are composing a word, it's 218932f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we 219032f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // should just skip whitespace if any, so 1. 219132f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // TODO: this is slow (2-way IPC) - we should probably cache this instead. 2192bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String prevWord = 2193ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 219432f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard mWordComposer.isComposingWord() ? 2 : 1); 2195ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard return mSuggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(), 21962dbb5957e3c8354fa9bcb1e08c7ce81387b7fe25Jean Chalard mSettings.getBlockPotentiallyOffensive(), 2197ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard mSettings.getCurrent().mCorrectionEnabled, sessionId); 2198ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard } 2199ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard 2200ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) { 2201ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard return maybeRetrieveOlderSuggestions(mWordComposer.getTypedWord(), 2202ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard getSuggestedWords(sessionId)); 22037ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard } 2204979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2205bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord, 220632f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard final SuggestedWords suggestedWords) { 220732f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // TODO: consolidate this into getSuggestedWords 220809fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // We update the suggestion strip only when we have some suggestions to show, i.e. when 220909fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // the suggestion count is > 1; else, we leave the old suggestions, with the typed word 221009fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // replaced with the new one. However, when the word is a dictionary word, or when the 221109fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // length of the typed word is 1 or 0 (after a deletion typically), we do want to remove the 221209fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // old suggestions. Also, if we are showing the "add to dictionary" hint, we need to 221309fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // revert to suggestions - although it is unclear how we can come here if it's displayed. 221409fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard if (suggestedWords.size() > 1 || typedWord.length() <= 1 2215ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard || suggestedWords.mTypedWordValid || null == mSuggestionStripView 22164702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka || mSuggestionStripView.isShowingAddToDictionaryHint()) { 2217ea80794dd43d44fe53884b4b8f4567af3d0e8331Jean Chalard return suggestedWords; 2218838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard } else { 2219f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka return getOlderSuggestions(typedWord); 22209fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka } 2221979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 22224a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 2223f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka private SuggestedWords getOlderSuggestions(final String typedWord) { 2224abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard SuggestedWords previousSuggestedWords = mSuggestedWords; 2225abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard if (previousSuggestedWords == mSettings.getCurrent().mSuggestPuncList) { 2226abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard previousSuggestedWords = SuggestedWords.EMPTY; 2227f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka } 2228f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka if (typedWord == null) { 2229abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard return previousSuggestedWords; 2230f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka } 2231f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = 2232abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, 2233abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard previousSuggestedWords); 2234f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka return new SuggestedWords(typedWordAndPreviousSuggestions, 2235f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka false /* typedWordValid */, 2236f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka false /* hasAutoCorrectionCandidate */, 2237f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka false /* isPunctuationSuggestions */, 2238f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka true /* isObsoleteSuggestions */, 2239f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka false /* isPrediction */); 2240f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka } 2241f21a491ad80c99063e461056ce3cb0eaca1a41e2Tadashi G. Takaoka 2242bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private void showSuggestionStrip(final SuggestedWords suggestedWords, final String typedWord) { 2243c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka if (suggestedWords.isEmpty()) { 2244259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 22452c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard return; 22462c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard } 2247bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String autoCorrection; 2248c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka if (suggestedWords.mWillAutoCorrect) { 2249c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka autoCorrection = suggestedWords.getWord(1); 2250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 2251c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka autoCorrection = typedWord; 2252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2253d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard mWordComposer.setAutoCorrection(autoCorrection); 22549b01890254c62a30b079bd9f79a30f9541faf11bJean Chalard final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); 2255abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard setSuggestedWords(suggestedWords, isAutoCorrection); 2256dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 2257913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 2258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2260a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard private void commitCurrentAutoCorrection(final String separatorString) { 2261913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Complete any pending suggestions query first 2262d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka if (mHandler.hasPendingUpdateSuggestions()) { 2263259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka updateSuggestionStrip(); 2264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2265bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); 2266eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final String typedWord = mWordComposer.getTypedWord(); 2267bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String autoCorrection = (typedAutoCorrection != null) 2268eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang ? typedAutoCorrection : typedWord; 2269117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard if (autoCorrection != null) { 227046798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard if (TextUtils.isEmpty(typedWord)) { 227146798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard throw new RuntimeException("We have an auto-correction but the typed word " 227246798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard + "is empty? Impossible! I must commit suicide."); 227346798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard } 2274756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 22754aff3bf0eaf4aec38c1d8576fdfc85a9eaa1c544Kurt Partridge Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer); 227687cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 22779c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 2278abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard final SuggestedWords suggestedWords = mSuggestedWords; 22794aff3bf0eaf4aec38c1d8576fdfc85a9eaa1c544Kurt Partridge ResearchLogger.latinIme_commitCurrentAutoCorrection(typedWord, autoCorrection, 22800c16a5c6eef645fd536671994e0b4f05864ac338Kurt Partridge separatorString, mWordComposer.isBatchMode(), suggestedWords); 2281226377e65aabe3922c47a4e40f7d846d346c55d5Kurt Partridge } 2282f77dd424b077a7f8ff547c09cb94d0dc7f0daed7Kurt Partridge mExpectingUpdateSelection = true; 228366bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, 2284a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard separatorString); 22855475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!typedWord.equals(autoCorrection)) { 22861c6cf26c3705e845418a29718c034598b52293ccJean Chalard // This will make the correction flash for a short while as a visual clue 228728d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // to the user that auto-correction happened. It has no other effect; in particular 228828d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // note that this won't affect the text inside the text field AT ALL: it only makes 228928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // the segment of text starting at the supplied index and running for the length 229028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // of the auto-correction flash. At this moment, the "typedWord" argument is 229128d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // ignored by TextView. 22925475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCorrection( 22935475b38328171a0841ae18074bd45380ec567e90Jean Chalard new CorrectionInfo(mLastSelectionEnd - typedWord.length(), 229496fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasa typedWord, autoCorrection)); 22951c6cf26c3705e845418a29718c034598b52293ccJean Chalard } 2296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22994702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} 23004702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // interface 2301c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 23029310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard public void pickSuggestionManually(final int index, final SuggestedWordInfo suggestionInfo) { 2303abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard final SuggestedWords suggestedWords = mSuggestedWords; 23049310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard final String suggestion = suggestionInfo.mWord; 2305551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput 2306551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard if (suggestion.length() == 1 && isShowingPunctuationList()) { 2307551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Word separators are suggested before the user inputs something. 2308551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // So, LatinImeLogger logs "" as a user's input. 2309f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge LatinImeLogger.logOnManualSuggestion("", suggestion, index, suggestedWords); 2310551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. 2311551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard final int primaryCode = suggestion.charAt(0); 2312551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard onCodeInput(primaryCode, 2313ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); 23149c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 23153b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, 23163338703a2fe8fa3ae549e1d884d9fb5a579a7f74Kurt Partridge false /* isBatchMode */, suggestedWords.mIsPrediction); 231794e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 2318551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard return; 2319551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard } 2320551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard 23214fde56b8182514bcae64d76488724d2a64a73f14Jean Chalard mConnection.beginBatchEdit(); 2322eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0 2323eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // In the batch input mode, a manually picked suggested word should just replace 2324eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // the current batch input text and there is no need for a phantom space. 2325eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang && !mWordComposer.isBatchMode()) { 2326ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard final int firstChar = Character.codePointAt(suggestion, 0); 2327ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard if (!mSettings.getCurrent().isWordSeparator(firstChar) 2328ae3b96b26ef86a9f342b4aeb2047abdaac5e57a5Jean Chalard || mSettings.getCurrent().isUsuallyPrecededBySpace(firstChar)) { 23290e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 2330845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 2331845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 2332845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard 2333ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().isApplicationSpecifiedCompletionsOn() 2334dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mApplicationSpecifiedCompletions != null 23351b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka && index >= 0 && index < mApplicationSpecifiedCompletions.length) { 2336abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard mSuggestedWords = SuggestedWords.EMPTY; 23374702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) { 23384702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.clear(); 2339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2340b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 2341611a5bdf650f7bc54bf40176f84f1cd9c87aa9aaJean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 23425475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; 23435475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCompletion(completionInfo); 23449d71748ba48dbc8793f3e1ecddf5fd31b8e59613Jean Chalard mConnection.endBatchEdit(); 2345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 2346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 23476a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 2348af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // We need to log before we commit, because the word composer will store away the user 2349af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // typed word. 23504aff3bf0eaf4aec38c1d8576fdfc85a9eaa1c544Kurt Partridge final String replacedWord = mWordComposer.getTypedWord(); 2351f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge LatinImeLogger.logOnManualSuggestion(replacedWord, suggestion, index, suggestedWords); 235235c11842a78e272ac4f61bfc58b96826c833f104Kurt Partridge mExpectingUpdateSelection = true; 235335c11842a78e272ac4f61bfc58b96826c833f104Kurt Partridge commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, 235435c11842a78e272ac4f61bfc58b96826c833f104Kurt Partridge LastComposedWord.NOT_A_SEPARATOR); 23559c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 23563b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, 23573b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge mWordComposer.isBatchMode()); 235894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 23594fde56b8182514bcae64d76488724d2a64a73f14Jean Chalard mConnection.endBatchEdit(); 236029a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard // Don't allow cancellation of manual pick 236129a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard mLastComposedWord.deactivate(); 236290a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Space state must be updated before calling updateShiftState 2363fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 2364fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mKeyboardSwitcher.updateShiftState(); 2365979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2366c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // We should show the "Touch again to save" hint if the user pressed the first entry 2367491d451e382a8e7d42937a96e4e06ada483e57b5Jean Chalard // AND it's in none of our current dictionaries (main, user or otherwise). 23687f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // Please note that if mSuggest is null, it means that everything is off: suggestion 23697f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // and correction, so we shouldn't try to show the hint 23709310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard final boolean showingAddToDictionaryHint = 23719310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard SuggestedWordInfo.KIND_TYPED == suggestionInfo.mKind && mSuggest != null 2372491d451e382a8e7d42937a96e4e06ada483e57b5Jean Chalard // If the suggestion is not in the dictionary, the hint should be shown. 2373491d451e382a8e7d42937a96e4e06ada483e57b5Jean Chalard && !AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(), suggestion, true); 2374b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 2375756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 2376240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Stats.onSeparator((char)Constants.CODE_SPACE, 237787cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 237887cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 2379b1dc8ad5f244337f91fcdac2a17078f5b9239cb7Jean Chalard if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { 23804702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.showAddToDictionaryHint( 2381ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka suggestion, mSettings.getCurrent().mHintToSaveText); 2382b1dc8ad5f244337f91fcdac2a17078f5b9239cb7Jean Chalard } else { 23838f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // If we're not showing the "Touch again to save", then update the suggestion strip. 2384a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 238566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 2386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2387a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2388979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 23898558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa * Commits the chosen word to the text field and saves it for later retrieval. 2390979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 2391bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private void commitChosenWord(final String chosenWord, final int commitType, 2392a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard final String separatorString) { 2393abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard final SuggestedWords suggestedWords = mSuggestedWords; 2394e8bb8351d6f09f461851af619cabe5fcd2f66c0aJean Chalard mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( 2395e8bb8351d6f09f461851af619cabe5fcd2f66c0aJean Chalard this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); 2396c54d558e2e70bdfb2c1078cae7b88440d421dc67satok // Add the word to the user history dictionary 2397bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String prevWord = addToUserHistoryDictionary(chosenWord); 23980fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // TODO: figure out here if this is an auto-correct or if the best word is actually 23990fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // what user typed. Note: currently this is done much later in 2400bdf89ce5feedb03e67b43f530b1eb9bd44203c63Jean Chalard // LastComposedWord#didCommitTypedWord by string equality of the remembered 24010fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // strings. 24024aff3bf0eaf4aec38c1d8576fdfc85a9eaa1c544Kurt Partridge mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord, separatorString, 24034aff3bf0eaf4aec38c1d8576fdfc85a9eaa1c544Kurt Partridge prevWord); 2404923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2405923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2406a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private void setPunctuationSuggestions() { 2407ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (mSettings.getCurrent().mBigramPredictionEnabled) { 2408259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 2409d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard } else { 2410abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard setSuggestedWords(mSettings.getCurrent().mSuggestPuncList, false); 2411d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard } 24127204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 2413913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 24146a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 24156a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 2416bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String addToUserHistoryDictionary(final String suggestion) { 2417c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (TextUtils.isEmpty(suggestion)) return null; 2418e46d12927ee2717788248b05f00b751beaf2a02aKen Wakasa if (mSuggest == null) return null; 2419bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 2420ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // If correction is not enabled, we don't add words to the user history dictionary. 2421ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // That's to avoid unintended additions in some sensitive fields, or fields that 2422ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // expect to receive non-words. 2423ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka if (!mSettings.getCurrent().mCorrectionEnabled) return null; 2424bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 2425a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka final Suggest suggest = mSuggest; 242667b9337b6cc478973d2c628fb5686583ce339bf0Satoshi Kataoka final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; 2427a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka if (suggest == null || userHistoryDictionary == null) { 2428a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka // Avoid concurrent issue 2429a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka return null; 2430a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka } 2431a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka final String prevWord 2432a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka = mConnection.getNthPreviousWord(mSettings.getCurrent().mWordSeparators, 2); 2433a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka final String secondWord; 2434a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { 2435a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); 2436a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka } else { 2437a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka secondWord = suggestion; 2438a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka } 2439a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". 2440a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka // We don't add words with 0-frequency (assuming they would be profanity etc.). 2441a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka final int maxFreq = AutoCorrection.getMaxFrequency( 2442a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka suggest.getUnigramDictionaries(), suggestion); 2443a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka if (maxFreq == 0) return null; 2444a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0); 2445a17dccbfc624c991ca054a5436519e74e0a60b54Satoshi Kataoka return prevWord; 244632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 244732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani 24486b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 24496a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard * Check if the cursor is touching a word. If so, restart suggestions on this word, else 24506a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard * do nothing. 24516a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard */ 24526a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard private void restartSuggestionsOnWordTouchedByCursor() { 245389fe1f50881180730e451cbe6ec4d1f8dc67acf1Jean Chalard // HACK: We may want to special-case some apps that exhibit bad behavior in case of 245489fe1f50881180730e451cbe6ec4d1f8dc67acf1Jean Chalard // recorrection. This is a temporary, stopgap measure that will be removed later. 245589fe1f50881180730e451cbe6ec4d1f8dc67acf1Jean Chalard // TODO: remove this. 245689fe1f50881180730e451cbe6ec4d1f8dc67acf1Jean Chalard if (mAppWorkAroundsUtils.isBrokenByRecorrection()) return; 24576a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard // If the cursor is not touching a word, or if there is a selection, return right away. 24586a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard if (mLastSelectionStart != mLastSelectionEnd) return; 24599f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard // If we don't know the cursor location, return. 24609f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard if (mLastSelectionStart < 0) return; 24616a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return; 24626a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(), 24636a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 0 /* additionalPrecedingWordsCount */); 24642b42ad0eaa5398853fd7d87a2580226d784a55ebJean Chalard if (null == range) return; // Happens if we don't have an input connection at all 24659f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard // If for some strange reason (editor bug or so) we measure the text before the cursor as 24669f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard // longer than what the entire text is supposed to be, the safe thing to do is bail out. 24679f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard if (range.mCharsBefore > mLastSelectionStart) return; 24686a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList(); 24690e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard final String typedWord = range.mWord.toString(); 24706a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard if (range.mWord instanceof SpannableString) { 24716a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard final SpannableString spannableString = (SpannableString)range.mWord; 24726a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard int i = 0; 24736a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard for (Object object : spannableString.getSpans(0, spannableString.length(), 24746a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard SuggestionSpan.class)) { 24756a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard SuggestionSpan span = (SuggestionSpan)object; 24766a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard for (String s : span.getSuggestions()) { 24776a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard ++i; 24786a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard if (!TextUtils.equals(s, typedWord)) { 24796a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard suggestions.add(new SuggestedWordInfo(s, 24806a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard SuggestionStripView.MAX_SUGGESTIONS - i, 24816a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard SuggestedWordInfo.KIND_RESUMED, Dictionary.TYPE_RESUMED)); 24826a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 24836a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 24846a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 24856a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 24860e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard()); 24876a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mWordComposer.setCursorPositionWithinWord(range.mCharsBefore); 24886a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore, 24896a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard mLastSelectionEnd + range.mCharsAfter); 24900e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard final SuggestedWords suggestedWords; 24916a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard if (suggestions.isEmpty()) { 24920e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // We come here if there weren't any suggestion spans on this word. We will try to 24930e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // compute suggestions for it instead. 24940e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard final SuggestedWords suggestedWordsIncludingTypedWord = 24950e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard getSuggestedWords(Suggest.SESSION_TYPING); 24960e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard if (suggestedWordsIncludingTypedWord.size() > 1) { 24970e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // We were able to compute new suggestions for this word. 24980e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // Remove the typed word, since we don't want to display it in this case. 24990e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // The #getSuggestedWordsExcludingTypedWord() method sets willAutoCorrect to false. 25000e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard suggestedWords = 25010e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard suggestedWordsIncludingTypedWord.getSuggestedWordsExcludingTypedWord(); 25020e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } else { 25030e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // No saved suggestions, and we were unable to compute any good one either. 25040e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // Rather than displaying an empty suggestion strip, we'll display the original 25050e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // word alone in the middle. 25060e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // Since there is only one word, willAutoCorrect is false. 25070e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard suggestedWords = suggestedWordsIncludingTypedWord; 25080e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } 25090e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard } else { 25100e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // We found suggestion spans in the word. We'll create the SuggestedWords out of 25110e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // them, and make willAutoCorrect false. 25120e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard suggestedWords = new SuggestedWords(suggestions, 25130e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard true /* typedWordValid */, false /* willAutoCorrect */, 25140e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, 25150e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard false /* isPrediction */); 25166a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 25170e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard 25180e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // Note that it's very important here that suggestedWords.mWillAutoCorrect is false. 25190e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard // We never want to auto-correct on a resumed suggestion. Please refer to the three 2520b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // places above where suggestedWords is affected. We also need to reset 2521b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // mIsAutoCorrectionIndicatorOn to avoid showSuggestionStrip touching the text to adapt it. 2522b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard // TODO: remove mIsAutoCorrectionIndicator on (see comment on definition) 2523b1e37e4a478a577c59930767148e50f8f45af21fJean Chalard mIsAutoCorrectionIndicatorOn = false; 25240e9ee4d3bf75459560670ca5c28ff4c4f7c346fbJean Chalard showSuggestionStrip(suggestedWords, typedWord); 25256a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard } 25266a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard 25276a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard /** 25286b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Check if the cursor is actually at the end of a word. If so, restart suggestions on this 25296b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * word, else do nothing. 25306b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 25315475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() { 2532ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final CharSequence word = 2533ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mConnection.getWordBeforeCursorIfAtEndOfWord(mSettings.getCurrent()); 2534747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard if (null != word) { 25356a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard final String wordString = word.toString(); 25366a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard restartSuggestionsOnWordBeforeCursor(wordString); 25373b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge // TODO: Handle the case where the user manually moves the cursor and then backs up over 25383b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge // a separator. In that case, the current log unit should not be uncommitted. 25399c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 25406a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard ResearchLogger.getInstance().uncommitCurrentLogUnit(wordString, 25413b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge true /* dumpCurrentLogUnit */); 25423b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge } 2543fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard } 25446b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 25456b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 25466a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard private void restartSuggestionsOnWordBeforeCursor(final String word) { 25473708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); 2548d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int length = word.length(); 25495475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(length, 0); 25505475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(word, 1); 2551a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 25526b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 25536b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 25545475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void revertCommit() { 2555bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String previousWord = mLastComposedWord.mPrevWord; 2556b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard final String originallyTypedWord = mLastComposedWord.mTypedWord; 2557bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String committedWord = mLastComposedWord.mCommittedWord; 2558cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final int cancelLength = committedWord.length(); 2559ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok final int separatorLength = LastComposedWord.getSeparatorLength( 2560a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mLastComposedWord.mSeparatorString); 2561193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // TODO: should we check our saved separator against the actual contents of the text view? 2562d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int deleteLength = cancelLength + separatorLength; 2563890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2564b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard if (mWordComposer.isComposingWord()) { 25655935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit, but we are composing a word"); 2566b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard } 2567bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final CharSequence wordBeforeCursor = 25685475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.getTextBeforeCursor(deleteLength, 0) 2569bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka .subSequence(0, cancelLength); 2570cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard if (!TextUtils.equals(committedWord, wordBeforeCursor)) { 25715935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit check failed: we thought we were " 2572cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard + "reverting \"" + committedWord 2573890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); 2574890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 25758558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa } 25765475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(deleteLength, 0); 2577c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { 2578f763dc5915d394378bdcdc90cc0b238e66926b8bKurt Partridge mUserHistoryDictionary.cancelAddingUserHistory(previousWord, committedWord); 2579c54d558e2e70bdfb2c1078cae7b88440d421dc67satok } 2580a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1); 2581756791e6bf80c1fd86f9a236f4ba8da770a7305fSatoshi Kataoka if (mSettings.isInternal()) { 258287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onSeparator(mLastComposedWord.mSeparatorString, 258387cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 258487cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 25859c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 25863b95eaf70b0a11b1c6e0c52361fe738b4a4b2aceKurt Partridge ResearchLogger.latinIME_revertCommit(committedWord, originallyTypedWord, 258731156c816e57fc1824f32f26f0301bc21a402774Kurt Partridge mWordComposer.isBatchMode(), mLastComposedWord.mSeparatorString); 258875e69753b709c19d5a23baf88ec3ac2576ee9c24Kurt Partridge ResearchLogger.getInstance().uncommitCurrentLogUnit(committedWord, 258975e69753b709c19d5a23baf88ec3ac2576ee9c24Kurt Partridge true /* dumpCurrentLogUnit */); 2590193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } 25910e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // Don't restart suggestion yet. We'll restart if the user deletes the 25920e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // separator. 2593b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 2594746e014eb54f0d6278b948868dff4863bfe85ad8Jean Chalard // We have a separator between the word and the cursor: we should show predictions. 2595a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 2596890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2597890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 25980e84041bf740590230198fa845d8c45acd4cb586Jean Chalard // This essentially inserts a space, and that's it. 25990e84041bf740590230198fa845d8c45acd4cb586Jean Chalard public void promotePhantomSpace() { 260073ec85b8ad3102ce1c7e6013be73afe83475e589Jean Chalard if (mSettings.getCurrent().shouldInsertSpacesAutomatically() 260173ec85b8ad3102ce1c7e6013be73afe83475e589Jean Chalard && !mConnection.textBeforeCursorLooksLikeURL()) { 2602e36af707c8a8705ebd19fcc359c51181f7ebd171Jean Chalard sendKeyCodePoint(Constants.CODE_SPACE); 26039c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 260499931201d0258ec93bd47de6f6f53ad59709bd85Kurt Partridge ResearchLogger.latinIME_promotePhantomSpace(); 260599931201d0258ec93bd47de6f6f53ad59709bd85Kurt Partridge } 2606ec60d60078b4837b657dc207bdbde1748749199eJean Chalard } 26070e84041bf740590230198fa845d8c45acd4cb586Jean Chalard } 26080e84041bf740590230198fa845d8c45acd4cb586Jean Chalard 2609a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Used by the RingCharBuffer 2610f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean isWordSeparator(final int code) { 2611ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka return mSettings.getCurrent().isWordSeparator(code); 2612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 26149fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka // TODO: Make this private 26159fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka // Outside LatinIME, only used by the {@link InputTestsBase} test suite. 261615f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting 26179fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka void loadKeyboard() { 2618d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard // TODO: Why are we calling {@link #loadSettings()} and {@link #initSuggest()} in a 2619d91268ad9fb69b4733044b4e466e1d33f6c4725fJean Chalard // different order than in {@link #onStartInputView}? 26200657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka initSuggest(); 26210657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka loadSettings(); 262227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mKeyboardSwitcher.getMainKeyboardView() != null) { 26231e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // Reload keyboard because the current language has been changed. 2624ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent()); 26251e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka } 2626b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // Since we just changed languages, we should re-evaluate suggestions with whatever word 2627b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // we are currently composing. If we are not composing anything, we may want to display 26288f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway). 2629a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 263036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 263136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 2632a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback called by PointerTracker through the KeyboardActionListener. This is called when a 2633a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // key is depressed; release matching call is onReleaseKey below. 26345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 263541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka public void onPressKey(final int primaryCode, final boolean isSinglePointer) { 263641016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer); 2637923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2639a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback by PointerTracker through the KeyboardActionListener. This is called when a key 2640a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // is released; press matching call is onPressKey above. 26415a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 2642f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onReleaseKey(final int primaryCode, final boolean withSliding) { 26432a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); 26448d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 26458d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv // If accessibility is on, ensure the user receives keyboard state updates. 26468d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 26478d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (primaryCode) { 2648240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 26498d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); 26508d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 2651240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SWITCH_ALPHA_SYMBOL: 26528d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); 26538d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 26548d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 26558d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2656978c96aa995015658070346b60826a3a34fdaf84Jean Chalard 2657240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_DELETE == primaryCode) { 2658978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // This is a stopgap solution to avoid leaving a high surrogate alone in a text view. 2659978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // In the future, we need to deprecate deteleSurroundingText() and have a surrogate 2660978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // pair-friendly way of deleting characters in InputConnection. 2661e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard // TODO: use getCodePointBeforeCursor instead to improve performance 26625475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastChar = mConnection.getTextBeforeCursor(1, 0); 26635475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) { 26645475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 2665978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2666978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2667923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2668a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2669cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // Hooks for hardware keyboard 2670cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard @Override 2671cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard public boolean onKeyDown(final int keyCode, final KeyEvent event) { 26722fc4d422e72cf88bd4b0e30bce2a9815b7856b8eJean Chalard if (!ProductionFlag.IS_HARDWARE_KEYBOARD_SUPPORTED) return super.onKeyDown(keyCode, event); 2673cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // onHardwareKeyEvent, like onKeyDown returns true if it handled the event, false if 2674cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // it doesn't know what to do with it and leave it to the application. For example, 2675cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // hardware key events for adjusting the screen's brightness are passed as is. 2676976a42b873215a669fe22709960aa1259292d75cJean Chalard if (mEventInterpreter.onHardwareKeyEvent(event)) { 2677976a42b873215a669fe22709960aa1259292d75cJean Chalard final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); 2678976a42b873215a669fe22709960aa1259292d75cJean Chalard mCurrentlyPressedHardwareKeys.add(keyIdentifier); 2679976a42b873215a669fe22709960aa1259292d75cJean Chalard return true; 2680976a42b873215a669fe22709960aa1259292d75cJean Chalard } 2681cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard return super.onKeyDown(keyCode, event); 2682cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard } 2683cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard 2684cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard @Override 2685cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard public boolean onKeyUp(final int keyCode, final KeyEvent event) { 2686976a42b873215a669fe22709960aa1259292d75cJean Chalard final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); 2687976a42b873215a669fe22709960aa1259292d75cJean Chalard if (mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) { 2688976a42b873215a669fe22709960aa1259292d75cJean Chalard return true; 2689976a42b873215a669fe22709960aa1259292d75cJean Chalard } 2690cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard return super.onKeyUp(keyCode, event); 2691cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard } 2692cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard 2693cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // onKeyDown and onKeyUp are the main events we are interested in. There are two more events 2694cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // related to handling of hardware key events that we may want to implement in the future: 2695cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // boolean onKeyLongPress(final int keyCode, final KeyEvent event); 2696cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard // boolean onKeyMultiple(final int keyCode, final int count, final KeyEvent event); 2697cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard 2698123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka // receive ringer mode change and network state change. 2699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private BroadcastReceiver mReceiver = new BroadcastReceiver() { 2700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 2701f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onReceive(final Context context, final Intent intent) { 2702123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final String action = intent.getAction(); 2703564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2704123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka mSubtypeSwitcher.onNetworkStateChanged(intent); 270521af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 27068e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka mKeyboardSwitcher.onRingerModeChanged(); 2707123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } 2708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 2710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2711c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka private void launchSettings() { 27123c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge handleClose(); 27133c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(SettingsActivity.class); 2714466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2715466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2716f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void launchKeyboardedDialogActivity(final Class<? extends Activity> activityClass) { 27173c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge // Put the text in the attached EditText into a safe, saved state before switching to a 27183c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge // new activity that will also use the soft keyboard. 27193c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge commitTyped(LastComposedWord.NOT_A_SEPARATOR); 27203c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(activityClass); 27213c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge } 27223c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge 2723f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void launchSubActivity(final Class<? extends Activity> activityClass) { 2724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Intent intent = new Intent(); 27253c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge intent.setClass(LatinIME.this, activityClass); 272640651c8cf7d4296927f9c49aaa57bcfc7b5372caTadashi G. Takaoka intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 272740651c8cf7d4296927f9c49aaa57bcfc7b5372caTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 272840651c8cf7d4296927f9c49aaa57bcfc7b5372caTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 2729923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project startActivity(intent); 2730923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 27322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showSubtypeSelectorAndSettings() { 273385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 273485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 273585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka // TODO: Should use new string "Select active input modes". 273685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.language_selection_title), 27373c8117c88fc738f841ac43f5a88602a99b901feeSatoshi Kataoka getString(Utils.getAcitivityTitleResId(this, SettingsActivity.class)), 273885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 273985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 27402fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka @Override 27412fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka public void onClick(DialogInterface di, int position) { 27422fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka di.dismiss(); 27432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka switch (position) { 274485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 2745298b4240f84344bbcd70b72dfb20806ba93ffd22Tadashi G. Takaoka final Intent intent = IntentUtils.getInputLanguageSelectionIntent( 27466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mRichImm.getInputMethodIdOfThisIme(), 27472a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Intent.FLAG_ACTIVITY_NEW_TASK 27482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 27492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 27502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka startActivity(intent); 27512fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2752aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa case 1: 2753aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa launchSettings(); 2754aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa break; 27552fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 27562fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 275785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2758bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2759bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2760bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2761724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge showOptionDialog(builder.create()); 27622fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 2763923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2764f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void showOptionDialog(final AlertDialog dialog) { 276527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final IBinder windowToken = mKeyboardSwitcher.getMainKeyboardView().getWindowToken(); 276627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (windowToken == null) { 276727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka return; 276827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 276913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 277013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCancelable(true); 277113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCanceledOnTouchOutside(true); 277213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 277313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final Window window = dialog.getWindow(); 277413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final WindowManager.LayoutParams lp = window.getAttributes(); 277513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.token = windowToken; 277613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 277713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.setAttributes(lp); 277813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 277913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 278013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka mOptionsDialog = dialog; 278113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.show(); 278213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka } 278313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 2784abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard // TODO: can this be removed somehow without breaking the tests? 2785abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard @UsedForTesting 2786abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard /* package for test */ String getFirstSuggestedWord() { 2787abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard return mSuggestedWords.size() > 0 ? mSuggestedWords.getWord(0) : null; 2788abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard } 2789abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard 279028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard public void debugDumpStateAndCrashWithException(final String context) { 27917058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard final StringBuilder s = new StringBuilder(mAppWorkAroundsUtils.toString()); 27927058b02a9c798c21b169b778be2befc7739f4e9bJean Chalard s.append("\nAttributes : ").append(mSettings.getCurrent().mInputAttributes) 279328d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard .append("\nContext : ").append(context); 279428d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard throw new RuntimeException(s.toString()); 279528d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard } 279628d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard 27977e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 2798f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka protected void dump(final FileDescriptor fd, final PrintWriter fout, final String[] args) { 2799923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.dump(fd, fout, args); 2800a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project final Printer p = new PrintWriterPrinter(fout); 2802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println("LatinIME state :"); 28033708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2804df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; 2805df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka p.println(" Keyboard mode = " + keyboardMode); 2806ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka final SettingsValues settingsValues = mSettings.getCurrent(); 2807fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard p.println(" mIsSuggestionsSuggestionsRequested = " 2808ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka + settingsValues.isSuggestionsRequested(mDisplayOrientation)); 2809ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka p.println(" mCorrectionEnabled=" + settingsValues.mCorrectionEnabled); 28104d0f03bd66742ee292da81a3e025e119f28b6940Jean Chalard p.println(" isComposingWord=" + mWordComposer.isComposingWord()); 2811ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka p.println(" mSoundOn=" + settingsValues.mSoundOn); 2812ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka p.println(" mVibrateOn=" + settingsValues.mVibrateOn); 2813ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka p.println(" mKeyPreviewPopupOn=" + settingsValues.mKeyPreviewPopupOn); 2814ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka p.println(" inputAttributes=" + settingsValues.mInputAttributes); 2815923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 2817