LatinIME.java revision 7575ac70546c6a19331102a7719337614f5e3a0f
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 191cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.ImeOption.FORCE_ASCII; 201cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE; 211cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.ImeOption.NO_MICROPHONE_COMPAT; 221cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka 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; 31b224b60c94d85f30de93f66685adf06e662618c0Jean Chalardimport android.content.pm.ApplicationInfo; 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; 3981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaokaimport android.os.IBinder; 40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager; 43e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils; 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter; 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer; 484e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyCharacterMap; 494e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyEvent; 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 51c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.view.ViewGroup.LayoutParams; 5213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.Window; 5313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.WindowManager; 54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo; 5596fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasaimport android.view.inputmethod.CorrectionInfo; 56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo; 579cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 58c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 595ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils; 608d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 61c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils; 62c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper; 631fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils; 645c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 65c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 66c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 676b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 68c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 69f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 70c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView; 7116c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaokaimport com.android.inputmethod.latin.LocaleUtils.RunInLocale; 72c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 734702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionStripView; 746b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 76466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor; 77466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter; 784ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalardimport java.util.ArrayList; 79466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale; 80466741d8a78965b8509bf527344f289e50873092Mike LeBeau 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard. 83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 8413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokapublic class LatinIME extends InputMethodService implements KeyboardActionListener, 854702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener { 868efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka private static final String TAG = LatinIME.class.getSimpleName(); 87409220583333bdf06290dd9fd42f91b5c0d1b11asatok private static final boolean TRACE = false; 889e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka private static boolean DEBUG; 89a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 909e347d3d448e48229c46aad394ec9bd60cd5807bsatok private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; 91fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa 92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // How many continuous deletes at which to start deleting at a higher speed. 93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int DELETE_ACCELERATE_AT = 20; 94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Key events coming any faster than this are long-presses. 95d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani private static final int QUICK_PRESS = 200; 96a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 9759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private static final int PENDING_IMS_CALLBACK_DURATION = 800; 98055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 99cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /** 100cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * The name of the scheme used by the Package Manager to warn of a new package installation, 101cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * replacement or removal. 102cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard */ 103cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private static final String SCHEME_PACKAGE = "package"; 104cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 105fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_NONE = 0; 106120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Double space: the state where the user pressed space twice quickly, which LatinIME 107120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // resolved as period-space. Undoing this converts the period to a space. 108fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_DOUBLE = 1; 109b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip 110b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // have just been swapped. Undoing this swaps them back; the space is still considered weak. 111120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; 112fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak 113fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // spaces happen when the user presses space, accepting the current suggestion (whether 114fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // it's an auto-correction or not). 115fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_WEAK = 3; 116fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom space: a not-yet-inserted space that should get inserted on the next input, 117fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // character provided it's not a separator. If it's a separator, the phantom space is dropped. 118fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom spaces happen when a user chooses a word from the suggestion strip. 119fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_PHANTOM = 4; 120120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 121120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Current space state of the input method. This can be any of the above constants. 122120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private int mSpaceState; 123126698fdd256a2e3734634d3b923cabd800064baJean Chalard 124297e6d590bd957577c335aa8713a786145a70288Jean Chalard private SettingsValues mCurrentSettings; 12517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 126d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka private View mExtractArea; 127abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka private View mKeyPreviewBackingView; 128913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private View mSuggestionsContainer; 1294702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka private SuggestionStripView mSuggestionStripView; 130816a8a0fd85ca0327436f8bd1cfa6928600ebc5dJean Chalard /* package for tests */ Suggest mSuggest; 1311b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private CompletionInfo[] mApplicationSpecifiedCompletions; 132b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard private ApplicationInfo mTargetApplicationInfo; 133a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 134610f1dc8553cf2ed97e763a06a19380c4a6cd636satok private InputMethodManagerCompatWrapper mImm; 1352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private Resources mResources; 1362fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private SharedPreferences mPrefs; 137109728193e45262099cbf88d8d6fcc4ed05240caJean Chalard /* package for tests */ final KeyboardSwitcher mKeyboardSwitcher; 13889ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard private final SubtypeSwitcher mSubtypeSwitcher; 13981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private boolean mShouldSwitchToLastSubtype = true; 140a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1416a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka private boolean mIsMainDictionaryAvailable; 14267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private UserBinaryDictionary mUserDictionary; 1439ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard private UserHistoryDictionary mUserHistoryDictionary; 14488562bec54658840dcce352127bdc15705c20a89Jean Chalard private boolean mIsUserDictionaryAvailable; 14536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 1462692a8700737d8eed268039aa27b22a31669da08Jean Chalard private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 1479318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa private WordComposer mWordComposer = new WordComposer(); 148f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard private RichInputConnection mConnection = new RichInputConnection(this); 149409220583333bdf06290dd9fd42f91b5c0d1b11asatok 150979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Keep track of the last selection range to decide if we need to show word alternatives 15177da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private static final int NOT_A_CURSOR_POSITION = -1; 15277da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionStart = NOT_A_CURSOR_POSITION; 15377da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; 154979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1554733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't 1564733609947c0ec74e460bd714fffca0518ade93aJean Chalard // "expect" it, it means the user actually moved the cursor. 1574733609947c0ec74e460bd714fffca0518ade93aJean Chalard private boolean mExpectingUpdateSelection; 158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mDeleteCount; 159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private long mLastKeyTime; 160a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 161564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard private AudioAndHapticFeedbackManager mFeedbackManager; 16228f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 16338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Member variables for remembering the current device orientation. 16438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka private int mDisplayOrientation; 16538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 166cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Object for reacting to adding/removing a dictionary pack. 167cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private BroadcastReceiver mDictionaryPackInstallReceiver = 168cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard new DictionaryPackInstallBroadcastReceiver(this); 169cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 170dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Keeps track of most recently inserted text (multi-character key) for reverting 171dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani private CharSequence mEnteredText; 172dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 17370852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard private boolean mIsAutoCorrectionIndicatorOn; 174604d80c67185954d4691ac775be59c499eee3b1csatok 17513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka private AlertDialog mOptionsDialog; 17613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 1774f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public final UIHandler mHandler = new UIHandler(this); 178d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 1794f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { 18045f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_UPDATE_SHIFT_STATE = 1; 1814c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_PENDING_IMS_CALLBACK = 6; 182dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard private static final int MSG_UPDATE_SUGGESTION_STRIP = 7; 1834c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka 18410dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateSuggestions; 18510dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateShiftState; 18610dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private long mDoubleSpacesTurnIntoPeriodTimeout; 187c7564a787ea3d6722d763575928cd2631fda6277Jean Chalard private long mDoubleSpaceTimerStart; 18838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 1894f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UIHandler(LatinIME outerInstance) { 1904f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 19110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka } 192175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 19310dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka public void onCreate() { 19410dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka final Resources res = getOuterInstance().getResources(); 195175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateSuggestions = 196175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_suggestions); 197175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateShiftState = 198175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_shift_state); 199175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger( 200175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_double_spaces_turn_into_period_timeout); 2014f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 2024f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void handleMessage(Message msg) { 2054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 2064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; 207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 208dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard case MSG_UPDATE_SUGGESTION_STRIP: 209259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka latinIme.updateSuggestionStrip(); 210d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 211d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SHIFT_STATE: 212de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka switcher.updateShiftState(); 213d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 216d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 217a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard public void postUpdateSuggestionStrip() { 218dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions); 219d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 220d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 221d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard public void cancelUpdateSuggestionStrip() { 222dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard removeMessages(MSG_UPDATE_SUGGESTION_STRIP); 223d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 224d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 225d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public boolean hasPendingUpdateSuggestions() { 226dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard return hasMessages(MSG_UPDATE_SUGGESTION_STRIP); 227d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 228d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 229beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void postUpdateShiftState() { 230d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 231175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); 232d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 233d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 234d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateShiftState() { 235d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 236d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 237d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 238fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void startDoubleSpacesTimer() { 239c7564a787ea3d6722d763575928cd2631fda6277Jean Chalard mDoubleSpaceTimerStart = SystemClock.uptimeMillis(); 240fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 241fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 242fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void cancelDoubleSpacesTimer() { 243c7564a787ea3d6722d763575928cd2631fda6277Jean Chalard mDoubleSpaceTimerStart = 0; 244fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 245fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 246fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public boolean isAcceptingDoubleSpaces() { 247c7564a787ea3d6722d763575928cd2631fda6277Jean Chalard return SystemClock.uptimeMillis() - mDoubleSpaceTimerStart 248c7564a787ea3d6722d763575928cd2631fda6277Jean Chalard < mDoubleSpacesTurnIntoPeriodTimeout; 249fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 25038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 25159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Working variables for the following methods. 25259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mIsOrientationChanging; 2535fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard private boolean mPendingSuccessiveImsCallback; 25459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingStartInput; 25559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInputView; 25659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInput; 257e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private EditorInfo mAppliedEditorInfo; 25859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 25959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void startOrientationChanging() { 260dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka removeMessages(MSG_PENDING_IMS_CALLBACK); 261dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka resetPendingImsCallback(); 26259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = true; 263055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 264f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka if (latinIme.isInputViewShown()) { 265f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka latinIme.mKeyboardSwitcher.saveKeyboardState(); 266f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka } 26759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 26859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 26959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void resetPendingImsCallback() { 27059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = false; 27159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = false; 27259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = false; 27359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 27459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 275e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void executePendingImsCallback(LatinIME latinIme, EditorInfo editorInfo, 27659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka boolean restarting) { 27759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInputView) 27859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(mHasPendingFinishInput); 27959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInput) 28059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 28159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingStartInput) 282e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 28359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka resetPendingImsCallback(); 28459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 28559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 286e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 28759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 28859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the second onStartInput after orientation changed. 28959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = true; 29059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 29159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mIsOrientationChanging && restarting) { 29259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // This is the first onStartInput after orientation changed. 29359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = false; 2945fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = true; 29559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 29659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 297e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 298e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 299055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 300055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 301055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 302e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 3036b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK) 3046b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { 305e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // Typically this is the second onStartInputView after orientation changed. 306e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 307e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } else { 3085fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard if (mPendingSuccessiveImsCallback) { 309e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // This is the first onStartInputView after orientation changed. 3105fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = false; 311e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 312e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), 313e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka PENDING_IMS_CALLBACK_DURATION); 314e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 315e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 316e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 317e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputViewInternal(editorInfo, restarting); 318e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = editorInfo; 319e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 32059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 32159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 32259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 32359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 32459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInputView after orientation changed. 32559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = true; 32659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 32759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 32859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(finishingInput); 329e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = null; 33038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 33138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 332ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka 33359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 33459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 33559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInput after orientation changed. 33659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = true; 33759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 33859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 33959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka executePendingImsCallback(latinIme, null, false); 34059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 341ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 342ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 34338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 34438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 34589ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard public LatinIME() { 34689ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard super(); 34789ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 34889ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mKeyboardSwitcher = KeyboardSwitcher.getInstance(); 34989ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard } 35089ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard 3517e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 3527e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka public void onCreate() { 35327d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 35427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa mPrefs = prefs; 35527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa LatinImeLogger.init(this, prefs); 356c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 357223d671ffcfe182130742c8a48185b9362acc6f9Kurt Partridge ResearchLogger.getInstance().init(this, prefs, mKeyboardSwitcher); 358c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa } 359bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka InputMethodManagerCompatWrapper.init(this); 360ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka SubtypeSwitcher.init(this); 36127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa KeyboardSwitcher.init(this, prefs); 3622ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka AccessibilityUtils.init(this); 363363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 364923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onCreate(); 365363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 366bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka mImm = InputMethodManagerCompatWrapper.getInstance(); 36710dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka mHandler.onCreate(); 3689e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka DEBUG = LatinImeLogger.sDBG; 369363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 370363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka final Resources res = getResources(); 371363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka mResources = res; 372fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard 37328f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa loadSettings(); 37428f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 375297e6d590bd957577c335aa8713a786145a70288Jean Chalard ImfUtils.setAdditionalInputMethodSubtypes(this, mCurrentSettings.getAdditionalSubtypes()); 376f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka 3779502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 378979f8690967ff5409fe18f5085858ccdb8e0ccf1satok boolean tryGC = true; 379e86054e5c2e4734d87d2fbf1eeba8c75fc888df0Jean Chalard // Shouldn't this be removed? I think that from Honeycomb on, the GC is now actually working 380e86054e5c2e4734d87d2fbf1eeba8c75fc888df0Jean Chalard // as expected and this code is useless. 3819502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 382979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 3830ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 384979f8690967ff5409fe18f5085858ccdb8e0ccf1satok tryGC = false; 385979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (OutOfMemoryError e) { 3869502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e); 387979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 388979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 389979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 390f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = res.getConfiguration().orientation; 391b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 392cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Register to receive ringer mode change and network state change. 393cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Also receive installation and removal of a dictionary pack. 394123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final IntentFilter filter = new IntentFilter(); 395123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 39621af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project registerReceiver(mReceiver, filter); 398cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 399cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final IntentFilter packageFilter = new IntentFilter(); 400cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 401cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 402cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addDataScheme(SCHEME_PACKAGE); 403cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, packageFilter); 404646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard 405646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard final IntentFilter newDictFilter = new IntentFilter(); 406646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard newDictFilter.addAction( 407646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION); 408646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); 409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 41036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 41117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // Has to be package-visible for unit tests 41217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard /* package */ void loadSettings() { 4134f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 4144f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 41517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 416b0561ae98063f83684706886490ba5670138fcccJean Chalard final InputAttributes inputAttributes = 417b0561ae98063f83684706886490ba5670138fcccJean Chalard new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode()); 41816c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { 41916c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka @Override 42016c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka protected SettingsValues job(Resources res) { 421b0561ae98063f83684706886490ba5670138fcccJean Chalard return new SettingsValues(mPrefs, inputAttributes, LatinIME.this); 42216c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka } 42316c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka }; 424297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale()); 425297e6d590bd957577c335aa8713a786145a70288Jean Chalard mFeedbackManager = new AudioAndHapticFeedbackManager(this, mCurrentSettings); 42614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); 42717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 42817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 4290ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private void initSuggest() { 4306a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 4316a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final String localeStr = subtypeLocale.toString(); 43236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 43367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary oldContactsDictionary; 43478ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka if (mSuggest != null) { 43578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = mSuggest.getContactsDictionary(); 43678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.close(); 43778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } else { 43878ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = null; 43978ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 4406a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSuggest = new Suggest(this, subtypeLocale); 441ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard if (mCurrentSettings.mCorrectionEnabled) { 442297e6d590bd957577c335aa8713a786145a70288Jean Chalard mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); 44378ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 444e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 4456a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 4466080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4476080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge ResearchLogger.getInstance().initSuggest(mSuggest); 4486080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge } 4496a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka 45067fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary = new UserBinaryDictionary(this, localeStr); 45167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); 45278ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserDictionary(mUserDictionary); 453e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 45478ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka resetContactsDictionary(oldContactsDictionary); 455e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 4564f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 4574f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 4584f96bb4520de3610ae94da96b98e507ca7b76362satok if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 459b5afd3de0c20bce40a600357a15e8e8df0e62420Jean Chalard mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, mPrefs); 46078ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); 461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 46236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 46314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard /** 46414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * Resets the contacts dictionary in mSuggest according to the user settings. 46514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 4662e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * This method takes an optional contacts dictionary to use when the locale hasn't changed 4672e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * since the contacts dictionary can be opened or closed as necessary depending on the settings. 46814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 46914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * @param oldContactsDictionary an optional dictionary to use, or null 47014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard */ 47167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { 472297e6d590bd957577c335aa8713a786145a70288Jean Chalard final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict); 47314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 47467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary dictionaryToUse; 47514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (!shouldSetDictionary) { 47614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the dictionary is closed. If it is already closed, this is a no-op, 47714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // so it's safe to call it anyways. 47814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != oldContactsDictionary) oldContactsDictionary.close(); 47914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = null; 48014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 4812e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 4822e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang if (null != oldContactsDictionary) { 48367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard if (!oldContactsDictionary.mLocale.equals(locale)) { 48467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // If the locale has changed then recreate the contacts dictionary. This 48567fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // allows locale dependent rules for handling bigram name predictions. 48667fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.close(); 48705efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, locale); 4882e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } else { 48967fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // Make sure the old contacts dictionary is opened. If it is already open, 49067fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // this is a no-op, so it's safe to call it anyways. 49167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.reopen(this); 4922e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang dictionaryToUse = oldContactsDictionary; 4932e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } 49418222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } else { 49505efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, locale); 49618222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } 49714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 49814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 49914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != mSuggest) { 50014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard mSuggest.setContactsDictionary(dictionaryToUse); 50114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 502699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard } 503699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard 504cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /* package private */ void resetSuggestMainDict() { 5056a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 5066a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSuggest.resetMainDict(this, subtypeLocale); 5076a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 508cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard } 509cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 510466741d8a78965b8509bf527344f289e50873092Mike LeBeau @Override 511466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onDestroy() { 512e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa if (mSuggest != null) { 513e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.close(); 514e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest = null; 515979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 516923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project unregisterReceiver(mReceiver); 517cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard unregisterReceiver(mDictionaryPackInstallReceiver); 518979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 519979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.onDestroy(); 520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onDestroy(); 521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onConfigurationChanged(Configuration conf) { 525dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka mSubtypeSwitcher.onConfigurationChanged(conf); 526b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani // If orientation changed while predicting, commit the change 527f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka if (mDisplayOrientation != conf.orientation) { 528f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = conf.orientation; 529f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mHandler.startOrientationChanging(); 530f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 5315475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 5325475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.finishComposingText(); 5335475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 5342fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka if (isShowingOptionDialog()) 5352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka mOptionsDialog.dismiss(); 536b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 537923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onConfigurationChanged(conf); 538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 539b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public View onCreateInputView() { 5426c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka return mKeyboardSwitcher.onCreateInputView(); 5436c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka } 5446c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka 5456c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka @Override 5466c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka public void setInputView(View view) { 5476c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka super.setInputView(view); 548d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka mExtractArea = getWindow().getWindow().getDecorView() 549d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka .findViewById(android.R.id.extractArea); 550abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); 551913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer = view.findViewById(R.id.suggestions_container); 5524702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view); 5534702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) 5544702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.setListener(this, view); 555f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka if (LatinImeLogger.sVISUALDEBUG) { 556f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); 557f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka } 558923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 561c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public void setCandidatesView(View view) { 562c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka // To ensure that CandidatesView will never be set. 563c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return; 564923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 565923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 566a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker @Override 567e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 568e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInput(editorInfo, restarting); 56959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 57059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 57159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 572e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 573e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInputView(editorInfo, restarting); 57459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 57559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 57659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 57759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 57859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInputView(finishingInput); 57959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 58038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 58159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 58259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 58359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInput(); 58459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 58559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 5869cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka @Override 5879cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { 5884f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 5894f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 5906a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSubtypeSwitcher.updateSubtype(subtype); 5919cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka } 5929cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka 593e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) { 594e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInput(editorInfo, restarting); 59559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 59659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 5971cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka @SuppressWarnings("deprecation") 598e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { 599e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInputView(editorInfo, restarting); 60045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 601c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka MainKeyboardView inputView = switcher.getKeyboardView(); 6028e09172df1bb176cc899940862c56bed9b9aec4esatok 603ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (editorInfo == null) { 604ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.e(TAG, "Null EditorInfo in onStartInputView()"); 605ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (LatinImeLogger.sDBG) { 606ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok throw new NullPointerException("Null EditorInfo in onStartInputView()"); 607ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 608ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok return; 609ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 61089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (DEBUG) { 611ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.d(TAG, "onStartInputView: editorInfo:" 612ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok + String.format("inputType=0x%08x imeOptions=0x%08x", 613ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok editorInfo.inputType, editorInfo.imeOptions)); 614b6fb5eb391987f3e426649a892cdcbf781957f5asatok Log.d(TAG, "All caps = " 615b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) 616b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", sentence caps = " 617b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0) 618b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", word caps = " 619b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); 620910b73127fa207dd26ec8124000262523b0aac0csatok } 6219bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 62248a7681e064ae259b840f0e757da2d716043d893Kurt Partridge ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs); 6239bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 6241cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { 6254f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6264f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6271cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); 6284f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6291cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { 6304f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6314f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6324f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); 6334f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6344f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka 6351b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard mTargetApplicationInfo = 6361b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard TargetApplicationGetter.getCachedApplicationInfo(editorInfo.packageName); 6371b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard if (null == mTargetApplicationInfo) { 6381b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard new TargetApplicationGetter(this /* context */, this /* listener */) 6391b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard .execute(editorInfo.packageName); 6401b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard } 641b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 6427ef235f53f2291f22ddf8c56be9860a218b25bbbTadashi G. Takaoka LatinImeLogger.onStartInputView(editorInfo); 643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In landscape mode, this method gets called without the input view being created. 644979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (inputView == null) { 645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 646923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 647923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 648b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette // Forward this event to the accessibility utilities, if enabled. 649b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); 650b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette if (accessUtils.isTouchExplorationEnabled()) { 651e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka accessUtils.onStartInputViewInternal(editorInfo, restarting); 652b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette } 653b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette 6548d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka mSubtypeSwitcher.updateParametersOnStartInputView(); 6554ab730dbd34fad323063f2ffd31ce33de746668dsatok 656b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // The EditorInfo might have a flag that affects fullscreen mode. 657b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // Note: This call should be done by InputMethodService? 658b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka updateFullscreenMode(); 6591fead1d5f12928f90c723b5f7b88490cc7cd2a67Jean Chalard mLastSelectionStart = editorInfo.initialSelStart; 6601fead1d5f12928f90c723b5f7b88490cc7cd2a67Jean Chalard mLastSelectionEnd = editorInfo.initialSelEnd; 661ccc35f7fa74860a8d737a4e9ff01fc0168dd329dJean Chalard mApplicationSpecifiedCompletions = null; 662c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 663c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.closing(); 664c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mEnteredText = null; 6652692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 666c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mDeleteCount = 0; 667120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 668c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 66917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 67017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 671ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) { 672297e6d590bd957577c335aa8713a786145a70288Jean Chalard mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); 673549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka } 67417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 675297e6d590bd957577c335aa8713a786145a70288Jean Chalard switcher.loadKeyboard(editorInfo, mCurrentSettings); 676c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 6774702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) 6784702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.clear(); 679913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShownInternal( 680913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka isSuggestionsStripVisible(), /* needsInputViewShown */ false); 6818e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard 6828e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 683ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 684c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 685297e6d590bd957577c335aa8713a786145a70288Jean Chalard inputView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn, 686297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.mKeyPreviewPopupDismissDelay); 687c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.setProximityCorrectionEnabled(true); 688c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 689c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); 690c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 691c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 692a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback for the TargetApplicationGetter 6937214617622fce8f3fea6620e782c16336260a2a3Jean Chalard @Override 694b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard public void onTargetApplicationKnown(final ApplicationInfo info) { 695b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard mTargetApplicationInfo = info; 696b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard } 697b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 698923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 699e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka public void onWindowHidden() { 700d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 701d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.latinIME_onWindowHidden(mLastSelectionStart, mLastSelectionEnd, 702d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge getCurrentInputConnection()); 703d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 704e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka super.onWindowHidden(); 705f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 706e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka if (inputView != null) inputView.closing(); 707e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 708e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 70959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputInternal() { 710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onFinishInput(); 711a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 712979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 71307cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 7140df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge ResearchLogger.getInstance().latinIME_onFinishInputInternal(); 71507cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge } 716979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 717f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 718d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa if (inputView != null) inputView.closing(); 719466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 720466741d8a78965b8509bf527344f289e50873092Mike LeBeau 72159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputViewInternal(boolean finishingInput) { 7226495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa super.onFinishInputView(finishingInput); 723055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardSwitcher.onFinishInputView(); 724f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 7255f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (inputView != null) inputView.cancelAllMessages(); 726d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka // Remove pending messages related to update suggestions 727d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 7286495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa } 7296495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa 7306495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa @Override 731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onUpdateSelection(int oldSelStart, int oldSelEnd, 732923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int newSelStart, int newSelEnd, 733104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard int composingSpanStart, int composingSpanEnd) { 734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, 735104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard composingSpanStart, composingSpanEnd); 736466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (DEBUG) { 737466741d8a78965b8509bf527344f289e50873092Mike LeBeau Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart 738466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ose=" + oldSelEnd 739025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lss=" + mLastSelectionStart 740025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lse=" + mLastSelectionEnd 741466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nss=" + newSelStart 742466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nse=" + newSelEnd 743104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", cs=" + composingSpanStart 744104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", ce=" + composingSpanEnd); 745466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 7469bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 747d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge final boolean expectingUpdateSelectionFromLogger = 748d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.getAndClearLatinIMEExpectingUpdateSelection(); 7499bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, 7509bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, 751d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge composingSpanEnd, mExpectingUpdateSelection, 75202308bec632a5df23325c916bffec5def16b22b4Jean Chalard expectingUpdateSelectionFromLogger, mConnection); 753d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (expectingUpdateSelectionFromLogger) { 754e86054e5c2e4734d87d2fbf1eeba8c75fc888df0Jean Chalard // TODO: Investigate. Quitting now sounds wrong - we won't do the resetting work 755d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge return; 756d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 7579bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 758466741d8a78965b8509bf527344f289e50873092Mike LeBeau 759104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // TODO: refactor the following code to be less contrived. 760104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means 761104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // that the cursor is not at the end of the composing span, or there is a selection. 762104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place 763104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // as last time we were called (if there is a selection, it means the start hasn't 764104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // changed, so it's the end that did). 765104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean selectionChanged = (newSelStart != composingSpanEnd 766104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart; 767104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // if composingSpanStart and composingSpanEnd are -1, it means there is no composing 768104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // span in the view - we can use that to narrow down whether the cursor was moved 769104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // by us or not. If we are composing a word but there is no composing span, then 770104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // we know for sure the cursor moved while we were composing and we should reset 771104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // the state. 772104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1; 7734733609947c0ec74e460bd714fffca0518ade93aJean Chalard if (!mExpectingUpdateSelection) { 774cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // TAKE CARE: there is a race condition when we enter this test even when the user 775cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // did not explicitly move the cursor. This happens when typing fast, where two keys 776cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // turn this flag on in succession and both onUpdateSelection() calls arrive after 777cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // the second one - the first call successfully avoids this test, but the second one 778104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // enters. For the moment we rely on noComposingSpan to further reduce the impact. 77951fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 7809a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // TODO: the following is probably better done in resetEntireInputState(). 7819a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // it should only happen when the cursor moved, and the very purpose of the 7829a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // test below is to narrow down whether this happened or not. Likewise with 7839a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // the call to postUpdateShiftState. 78451fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // We set this to NONE because after a cursor move, we don't want the space 78551fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // state-related special processing to kick in. 78651fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard mSpaceState = SPACE_STATE_NONE; 78751fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 7888a3d369840d6061692a19ceb1eb7267a50a9e056Jean Chalard if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) { 7892649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetEntireInputState(); 7904c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 791beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 792beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 7934733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 7944733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = false; 7956b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not 7966b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // here. It would probably be too expensive to call directly here but we may want to post a 7976b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // message to delay it. The point would be to unify behavior between backspace to the 7986b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // end of a word and manually put the pointer at the end of the word. 799466741d8a78965b8509bf527344f289e50873092Mike LeBeau 800979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Make a note of the cursor position 801979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionStart = newSelStart; 802979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionEnd = newSelEnd; 8037a8dac55278cedd838be325f56b4c52d973c61f5satok } 8047a8dac55278cedd838be325f56b4c52d973c61f5satok 805c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 806c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has clicked on the extracted text view, 807c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * when running in fullscreen mode. The default implementation hides 808913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * the suggestions view when this happens, but only if the extracted text 809c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * editor has a vertical scroll bar because its text doesn't fit. 810c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 811913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 812c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 813c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 814c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedTextClicked() { 815fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; 816c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 817c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedTextClicked(); 818c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 819c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 820c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 821c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has performed a cursor movement in the 822c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * extracted text view, when it is running in fullscreen mode. The default 823913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * implementation hides the suggestions view when a vertical movement 824c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * happens, but only if the extracted text editor has a vertical scroll bar 825c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * because its text doesn't fit. 826c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 827913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 828c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 829c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 830c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedCursorMovement(int dx, int dy) { 831fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; 832c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 833c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedCursorMovement(dx, dy); 834c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 835c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void hideWindow() { 838979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 839c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mKeyboardSwitcher.onHideWindow(); 840979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 841923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (TRACE) Debug.stopMethodTracing(); 8426e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani if (mOptionsDialog != null && mOptionsDialog.isShowing()) { 8436e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog.dismiss(); 8446e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog = null; 8456e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.hideWindow(); 847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 8501b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) { 851979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG) { 852a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa Log.i(TAG, "Received completions:"); 853bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok if (applicationSpecifiedCompletions != null) { 854bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 855bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); 856bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok } 857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 8599bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 8609bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); 8619bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 862dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return; 863dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; 864dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (applicationSpecifiedCompletions == null) { 865259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 866dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard return; 867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 868dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard 869dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = 870dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard SuggestedWords.getFromApplicationSpecifiedCompletions( 871dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard applicationSpecifiedCompletions); 872dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final SuggestedWords suggestedWords = new SuggestedWords( 873dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard applicationSuggestedWords, 874dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* typedWordValid */, 875dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* hasAutoCorrectionCandidate */, 876dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isPunctuationSuggestions */, 877dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isObsoleteSuggestions */, 878dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isPrediction */); 879dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // When in fullscreen mode, show completions generated by the application 880dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final boolean isAutoCorrection = false; 881259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(suggestedWords, isAutoCorrection); 882dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard setAutoCorrectionIndicator(isAutoCorrection); 883dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // TODO: is this the right thing to do? What should we auto-correct to in 884dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // this case? This says to keep whatever the user typed. 885dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 886dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard setSuggestionStripShown(true); 887923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 888923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 889c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { 890913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // TODO: Modify this if we support suggestions with hard keyboard 891913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { 892c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 893433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final boolean inputViewShown = (keyboardView != null) ? keyboardView.isShown() : false; 894913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean shouldShowSuggestions = shown 895433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka && (needsInputViewShown ? inputViewShown : true); 8964b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka if (isFullscreenMode()) { 897913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 898913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.GONE); 8997a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } else { 900913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 901913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); 9027a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } 903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 905a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 906c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShown(boolean shown) { 907c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); 908543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa } 909543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa 910bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka private int getAdjustedBackingViewHeight() { 911bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka final int currentHeight = mKeyPreviewBackingView.getHeight(); 912bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka if (currentHeight > 0) { 913bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return currentHeight; 914c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 915c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 916c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final KeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 917bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka if (keyboardView == null) { 918bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return 0; 919bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka } 920c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int keyboardHeight = keyboardView.getHeight(); 921c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int suggestionsHeight = mSuggestionsContainer.getHeight(); 922c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int displayHeight = mResources.getDisplayMetrics().heightPixels; 923c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final Rect rect = new Rect(); 924c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); 925c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int notificationBarHeight = rect.top; 926c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight 927c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka - keyboardHeight; 928c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 929c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final LayoutParams params = mKeyPreviewBackingView.getLayoutParams(); 9304702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka params.height = mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight); 931c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.setLayoutParams(params); 932bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return params.height; 933c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 934c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 935543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa @Override 936923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onComputeInsets(InputMethodService.Insets outInsets) { 937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onComputeInsets(outInsets); 938f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 939913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (inputView == null || mSuggestionsContainer == null) 94046ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka return; 941b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int adjustedBackingHeight = getAdjustedBackingViewHeight(); 942b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); 943b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int backingHeight = backingGone ? 0 : adjustedBackingHeight; 944d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // In fullscreen mode, the height of the extract area managed by InputMethodService should 945d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // be considered. 946d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. 947d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0; 94859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0 94959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka : mSuggestionsContainer.getHeight(); 950d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extraHeight = extractHeight + backingHeight + suggestionsHeight; 951abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka int touchY = extraHeight; 9529e347d3d448e48229c46aad394ec9bd60cd5807bsatok // Need to set touchable region only if input view is being shown 953c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka final MainKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 954433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka if (keyboardView != null && keyboardView.isShown()) { 955913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { 95659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka touchY -= suggestionsHeight; 9579e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 9587a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka final int touchWidth = inputView.getWidth(); 959abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka final int touchHeight = inputView.getHeight() + extraHeight 9607a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka // Extend touchable region below the keyboard. 9617a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + EXTENDED_TOUCHABLE_REGION_HEIGHT; 96213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; 96313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight); 9649e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 96546ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.contentTopInsets = touchY; 96646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.visibleTopInsets = touchY; 967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 968a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 970979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean onEvaluateFullscreenMode() { 9719751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka // Reread resource value here, because this method is called by framework anytime as needed. 9729751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka final boolean isFullscreenModeAllowed = 973297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.isFullscreenModeAllowed(getResources()); 9749751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka return super.onEvaluateFullscreenMode() && isFullscreenModeAllowed; 97559010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka } 97659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka 97759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka @Override 97859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka public void updateFullscreenMode() { 97959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka super.updateFullscreenMode(); 980f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka 98159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka if (mKeyPreviewBackingView == null) return; 982549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka // In fullscreen mode, no need to have extra space to show the key preview. 98359010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka // If not, we should have extra space above the keyboard to show the key preview. 984549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); 985979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 986979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 9872649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // This will reset the whole input state to the starting state. It will clear 9884a5cb5c36a6a385ec0036981a0e93b0253e884b0Jean Chalard // the composing word, reset the last composed word, tell the inputconnection about it. 9892649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard private void resetEntireInputState() { 9902649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 991259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 9925475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.finishComposingText(); 9932649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard } 9942649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard 9952692a8700737d8eed268039aa27b22a31669da08Jean Chalard private void resetComposingState(final boolean alsoResetLastComposedWord) { 9962692a8700737d8eed268039aa27b22a31669da08Jean Chalard mWordComposer.reset(); 9972692a8700737d8eed268039aa27b22a31669da08Jean Chalard if (alsoResetLastComposedWord) 9982692a8700737d8eed268039aa27b22a31669da08Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 9992692a8700737d8eed268039aa27b22a31669da08Jean Chalard } 10002692a8700737d8eed268039aa27b22a31669da08Jean Chalard 1001a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private void commitTyped(final int separatorCode) { 1002196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) return; 10033651220327c051d8017045aa5e8919461507b3f8Jean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 10043651220327c051d8017045aa5e8919461507b3f8Jean Chalard if (typedWord.length() > 0) { 10055475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(typedWord, 1); 10065475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 10075475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_commitText(typedWord); 1008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1009c54d558e2e70bdfb2c1078cae7b88440d421dc67satok final CharSequence prevWord = addToUserHistoryDictionary(typedWord); 1010c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mLastComposedWord = mWordComposer.commitWord( 1011c54d558e2e70bdfb2c1078cae7b88440d421dc67satok LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), 1012c54d558e2e70bdfb2c1078cae7b88440d421dc67satok separatorCode, prevWord); 1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1014259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka updateSuggestionStrip(); 1015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1017a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from the KeyboardSwitcher which needs to know auto caps state to display 1018a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // the right layout. 1019553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka public int getCurrentAutoCapsState() { 1020297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; 102103ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 102203ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final EditorInfo ei = getCurrentInputEditorInfo(); 1023553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; 102403ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 102503ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final int inputType = ei.inputType; 1026553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) { 1027553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka return TextUtils.CAP_MODE_CHARACTERS; 1028553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka } 102903ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 103003ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final boolean noNeedToCheckCapsMode = (inputType & (InputType.TYPE_TEXT_FLAG_CAP_SENTENCES 103103ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka | InputType.TYPE_TEXT_FLAG_CAP_WORDS)) == 0; 1032553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if (noNeedToCheckCapsMode) return Constants.TextUtils.CAP_MODE_OFF; 103303ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 103416950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka // Avoid making heavy round-trip IPC calls of {@link InputConnection#getCursorCapsMode} 103516950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka // unless needed. 103616950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka if (mWordComposer.isComposingWord()) return Constants.TextUtils.CAP_MODE_OFF; 103716950d65c323f99507d97cb7f0403dc653e2506cTadashi G. Takaoka 103803ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // TODO: This blocking IPC call is heavy. Consider doing this without using IPC calls. 103903ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // Note: getCursorCapsMode() returns the current capitalization mode that is any 104003ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // combination of CAP_MODE_CHARACTERS, CAP_MODE_WORDS, and CAP_MODE_SENTENCES. 0 means none 104103ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka // of them. 10425475b38328171a0841ae18074bd45380ec567e90Jean Chalard return mConnection.getCursorCapsMode(inputType); 10431c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 10441c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1045bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard private void swapSwapperAndSpace() { 10465475b38328171a0841ae18074bd45380ec567e90Jean Chalard CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); 1047863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. 1048923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastTwo != null && lastTwo.length() == 2 1049863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard && lastTwo.charAt(0) == Keyboard.CODE_SPACE) { 10505475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 1051d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1052d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(2); 1053d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 10545475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(lastTwo.charAt(1) + " ", 1); 1055d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1056d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_swapSwapperAndSpaceWhileInBatchEdit(); 1057d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1058b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 10594ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 10604ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 10614ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1062bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard private boolean maybeDoubleSpace() { 10632f3a694e29ad5a63052a2f963327855fee099f55Jean Chalard if (!mCurrentSettings.mCorrectionEnabled) return false; 106472b358aa90191c10892612768e3595bc3a1ccb2dJean Chalard if (!mHandler.isAcceptingDoubleSpaces()) return false; 10655475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0); 1066923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastThree != null && lastThree.length() == 3 1067344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka && canBeFollowedByPeriod(lastThree.charAt(0)) 1068571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastThree.charAt(1) == Keyboard.CODE_SPACE 106972b358aa90191c10892612768e3595bc3a1ccb2dJean Chalard && lastThree.charAt(2) == Keyboard.CODE_SPACE) { 1070fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka mHandler.cancelDoubleSpacesTimer(); 10715475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 10725475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(". ", 1); 1073d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1074d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_doubleSpaceAutoPeriod(); 1075d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1076b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1077120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 1078923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1079120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return false; 1080923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1081a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1082344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka private static boolean canBeFollowedByPeriod(final int codePoint) { 1083344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: Check again whether there really ain't a better way to check this. 1084344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: This should probably be language-dependant... 1085344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka return Character.isLetterOrDigit(codePoint) 1086344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_SINGLE_QUOTE 1087344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_DOUBLE_QUOTE 1088344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS 1089344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET 1090344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET 1091344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; 1092344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka } 1093344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka 10944702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is 10954702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // pressed. 1096c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 10973d8e7a62fc6182c12ca28c29ceeee52ed4b9eea7Jean Chalard public boolean addWordToUserDictionary(String word) { 109867fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary.addWordToUserDictionary(word, 128); 1099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 11028fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean isAlphabet(int code) { 11038fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka return Character.isLetter(code); 1104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1105a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1106e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka private void onSettingsKeyPressed() { 1107cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return; 1108911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa showSubtypeSelectorAndSettings(); 11099a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11109a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1111cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa // Virtual codes representing custom requests. These are used in onCustomRequest() below. 1112cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; 1113cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa 1114cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa @Override 1115cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public boolean onCustomRequest(int requestCode) { 1116cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return false; 1117cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa switch (requestCode) { 1118cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa case CODE_SHOW_INPUT_METHOD_PICKER: 111955d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka if (ImfUtils.hasMultipleEnabledIMEsOrSubtypes( 112055d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka this, true /* include aux subtypes */)) { 112179efbed76f638be298493107fa2d0cd1b5eb529esatok mImm.showInputMethodPicker(); 1122cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return true; 11239a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1124cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 11259a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1126cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 11279a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11289a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 11299a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok private boolean isShowingOptionDialog() { 11309a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok return mOptionsDialog != null && mOptionsDialog.isShowing(); 11319a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11329a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 113305bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka private static int getActionId(Keyboard keyboard) { 113405bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE; 11357a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11367a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11378f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka private void performEditorAction(int actionId) { 11385475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.performEditorAction(actionId); 11395475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 11405475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_performEditorAction(actionId); 11417a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11427a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11437a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 114481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private void handleLanguageSwitchKey() { 1145297e6d590bd957577c335aa8713a786145a70288Jean Chalard final boolean includesOtherImes = mCurrentSettings.mIncludesOtherImesInLanguageSwitchList; 114681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final IBinder token = getWindow().getWindow().getAttributes().token; 114781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if (mShouldSwitchToLastSubtype) { 11489cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka final InputMethodSubtype lastSubtype = mImm.getLastInputMethodSubtype(); 1149ae2388c7f799ab565f63d3ba83abaf3300475fd0Tadashi G. Takaoka final boolean lastSubtypeBelongsToThisIme = 1150ae2388c7f799ab565f63d3ba83abaf3300475fd0Tadashi G. Takaoka ImfUtils.checkIfSubtypeBelongsToThisImeAndEnabled(this, lastSubtype); 115181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if ((includesOtherImes || lastSubtypeBelongsToThisIme) 115281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && mImm.switchToLastInputMethod(token)) { 115381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = false; 115481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else { 115581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mImm.switchToNextInputMethod(token, !includesOtherImes); 115681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 115781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 115881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else { 115981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mImm.switchToNextInputMethod(token, !includesOtherImes); 116081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 116181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 116281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka 11635475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void sendUpDownEnterOrBackspace(final int code) { 11644e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard final long eventTime = SystemClock.uptimeMillis(); 11655475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, 11664e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_DOWN, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 11674e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 11685475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, 11694e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_UP, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 11704e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 11714e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 11724e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard 11737a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void sendKeyCodePoint(int code) { 11747a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // TODO: Remove this special handling of digit letters. 11757a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. 11767a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (code >= '0' && code <= '9') { 11777a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka super.sendKeyChar((char)code); 11787a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return; 11797a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11807a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11815475b38328171a0841ae18074bd45380ec567e90Jean Chalard // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because 11825475b38328171a0841ae18074bd45380ec567e90Jean Chalard // we want to be able to compile against the Ice Cream Sandwich SDK. 11835475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (Keyboard.CODE_ENTER == code && mTargetApplicationInfo != null 11845475b38328171a0841ae18074bd45380ec567e90Jean Chalard && mTargetApplicationInfo.targetSdkVersion < 16) { 11855475b38328171a0841ae18074bd45380ec567e90Jean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 11865475b38328171a0841ae18074bd45380ec567e90Jean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 11875475b38328171a0841ae18074bd45380ec567e90Jean Chalard // reasons (there are race conditions with commits) but some applications are 11885475b38328171a0841ae18074bd45380ec567e90Jean Chalard // relying on this behavior so we continue to support it for older apps. 11895475b38328171a0841ae18074bd45380ec567e90Jean Chalard sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_ENTER); 11905475b38328171a0841ae18074bd45380ec567e90Jean Chalard } else { 11915475b38328171a0841ae18074bd45380ec567e90Jean Chalard final String text = new String(new int[] { code }, 0, 1); 11925475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, text.length()); 11935475b38328171a0841ae18074bd45380ec567e90Jean Chalard } 11945475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 11955475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_sendKeyCodePoint(code); 11967a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11977a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11987a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11995f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Implementation of {@link KeyboardActionListener}. 12005a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1201ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok public void onCodeInput(int primaryCode, int x, int y) { 1202175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final long when = SystemClock.uptimeMillis(); 1203571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { 1204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDeleteCount = 0; 1205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mLastKeyTime = when; 1207f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 1208fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge 1209c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 121007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); 1211fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge } 1212fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge 1213175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1214120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // The space state depends only on the last character pressed and its own previous 1215120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // state. Here, we revert the space state to neutral if the key is actually modifying 1216120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // the input contents (any non-shift key), which is what we should do for 1217120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // all inputs that do not result in a special state. Each character handling is then 1218120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // free to override the state as they see fit. 1219120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState = mSpaceState; 122070852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false; 1221ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1222ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa // TODO: Consolidate the double space timer, mLastKeyTime, and the space state. 1223ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa if (primaryCode != Keyboard.CODE_SPACE) { 1224ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 1225ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa } 1226ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1227c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 1229571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_DELETE: 1230120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1231120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleBackspace(spaceState); 12324189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka mDeleteCount++; 12334733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 123481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 1235140467b8b65eb9087a9b7f744dbb8a30481effe7Kurt Partridge LatinImeLogger.logOnDelete(x, y); 12364189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1237571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_SHIFT: 1238e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 12392a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka // Shift and symbol key is handled in onPressKey() and onReleaseKey(). 12404189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1241e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SETTINGS: 124293246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka onSettingsKeyPressed(); 12434189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1244d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka case Keyboard.CODE_SHORTCUT: 124593246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka mSubtypeSwitcher.switchToShortcutIME(); 12464189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 12477a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka case Keyboard.CODE_ACTION_ENTER: 12488f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(getActionId(switcher.getKeyboard())); 12497a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka break; 125005bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case Keyboard.CODE_ACTION_NEXT: 12518f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_NEXT); 125205bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka break; 125305bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case Keyboard.CODE_ACTION_PREVIOUS: 12548f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); 12554189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 125681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka case Keyboard.CODE_LANGUAGE_SWITCH: 125781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka handleLanguageSwitchKey(); 125881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka break; 1259724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge case Keyboard.CODE_RESEARCH: 1260724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1261724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge ResearchLogger.getInstance().presentResearchDialog(this); 1262724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge } 1263724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge break; 12644189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka default: 1265120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1266297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWordSeparator(primaryCode)) { 1267c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); 12684189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 12694be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (SPACE_STATE_PHANTOM == spaceState) { 12704be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka commitTyped(LastComposedWord.NOT_A_SEPARATOR); 12714be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 1272eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int keyX, keyY; 12738dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 12748dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { 1275eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang keyX = x; 1276eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang keyY = y; 12778dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } else { 1278eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang keyX = NOT_A_TOUCH_COORDINATE; 1279eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang keyY = NOT_A_TOUCH_COORDINATE; 12808dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } 1281eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang handleCharacter(primaryCode, keyX, keyY, spaceState); 12824189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 12834733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 128481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 12854733609947c0ec74e460bd714fffca0518ade93aJean Chalard break; 1286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1287eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka switcher.onCodeInput(primaryCode); 1288125de3dfdf548359de890247907f2e6f430008ecJean Chalard // Reset after any single keystroke, except shift and symbol-shift 1289125de3dfdf548359de890247907f2e6f430008ecJean Chalard if (!didAutoCorrect && primaryCode != Keyboard.CODE_SHIFT 1290125de3dfdf548359de890247907f2e6f430008ecJean Chalard && primaryCode != Keyboard.CODE_SWITCH_ALPHA_SYMBOL) 1291c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard mLastComposedWord.deactivate(); 1292dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = null; 1293e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard mConnection.endBatchEdit(); 1294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1295a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1296a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from PointerTracker through the KeyboardActionListener interface 12975a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 12988aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onTextInput(CharSequence text) { 1299f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 13005475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 13015475b38328171a0841ae18074bd45380ec567e90Jean Chalard text = specificTldProcessingOnTextInput(text); 1302fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == mSpaceState) { 13037a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 1304fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 13055475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, 1); 1306d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1307d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_commitText(text); 1308d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 13095475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 1310b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 13118cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); 1312120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1313dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = text; 13142692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 1315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 13174be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 13184be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka public void onStartBatchInput() { 13194be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.beginBatchEdit(); 13204be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (mWordComposer.isComposingWord()) { 13214be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka commitTyped(LastComposedWord.NOT_A_SEPARATOR); 13224be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mExpectingUpdateSelection = true; 13234be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka // TODO: Can we remove this? 13244be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mSpaceState = SPACE_STATE_PHANTOM; 13254be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 13264be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.endBatchEdit(); 1327eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // TODO: Should handle TextUtils.CAP_MODE_CHARACTER. 1328eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mWordComposer.setAutoCapitalized( 1329eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang getCurrentAutoCapsState() != Constants.TextUtils.CAP_MODE_OFF); 1330eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1331eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 1332eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang @Override 133310102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka public void onUpdateBatchInput(InputPointers batchPointers) { 1334eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mWordComposer.setBatchInputPointers(batchPointers); 13357575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWords(); 13367575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka showSuggestionStrip(suggestedWords, null); 13374be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 13384be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 13394be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 134010102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka public void onEndBatchInput(InputPointers batchPointers) { 134110102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka mWordComposer.setBatchInputPointers(batchPointers); 13427575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWords(); 13437575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka showSuggestionStrip(suggestedWords, null); 134410102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka if (suggestedWords == null || suggestedWords.size() == 0) { 134510102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka return; 134610102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka } 134710102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka final CharSequence text = suggestedWords.getWord(0); 134810102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka if (TextUtils.isEmpty(text)) { 134910102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka return; 135010102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka } 1351eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang mWordComposer.setBatchInputWord(text); 13524be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.beginBatchEdit(); 13534be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (SPACE_STATE_PHANTOM == mSpaceState) { 13544be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 13554be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 13564be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.setComposingText(text, 1); 13574be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mExpectingUpdateSelection = true; 13584be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.endBatchEdit(); 13594be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 13604be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mSpaceState = SPACE_STATE_PHANTOM; 13614be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 13624be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 13635475b38328171a0841ae18074bd45380ec567e90Jean Chalard private CharSequence specificTldProcessingOnTextInput(final CharSequence text) { 1364fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (text.length() <= 1 || text.charAt(0) != Keyboard.CODE_PERIOD 1365fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard || !Character.isLetter(text.charAt(1))) { 1366fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Not a tld: do nothing. 1367fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1368fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 136912d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // We have a TLD (or something that looks like this): make sure we don't add 137012d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // a space even if currently in phantom mode. 137112d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard mSpaceState = SPACE_STATE_NONE; 13725475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0); 1373fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (lastOne != null && lastOne.length() == 1 1374fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard && lastOne.charAt(0) == Keyboard.CODE_PERIOD) { 1375fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text.subSequence(1, text.length()); 1376fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else { 1377fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1378fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1379fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1380fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1381a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from PointerTracker through the KeyboardActionListener interface 13825a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13838aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() { 138483e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka // User released a finger outside any key 13855f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka mKeyboardSwitcher.onCancelInput(); 138683e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } 138783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka 1388120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleBackspace(final int spaceState) { 13892245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard // In many cases, we may have to put the keyboard in auto-shift state again. 1390beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 13912245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard 1392747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) { 13935c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // Cancel multi-character input: remove the text we just entered. 13945c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // This is triggered on backspace after a key that inputs multiple characters, 13955c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // like the smiley key or the .com key. 1396d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int length = mEnteredText.length(); 13975475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(length, 0); 1398d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1399d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(length); 1400d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 14015c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. 14025c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // In addition we know that spaceState is false, and that we should not be 14035c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // reverting any autocorrect at this point. So we can safely return. 14045c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard return; 14055c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard } 14065c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard 1407196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 14083651220327c051d8017045aa5e8919461507b3f8Jean Chalard final int length = mWordComposer.size(); 1409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (length > 0) { 14104be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka // Immediately after a batch input. 14114be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (SPACE_STATE_PHANTOM == spaceState) { 14124be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mWordComposer.reset(); 14134be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } else { 14144be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mWordComposer.deleteLast(); 14154be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 14165475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1417a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 14195475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1420d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1421d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(1); 1422d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1424890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } else { 14255935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard if (mLastComposedWord.canRevertCommit()) { 1426d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard Utils.Stats.onAutoCorrectionCancellation(); 14275475b38328171a0841ae18074bd45380ec567e90Jean Chalard revertCommit(); 1428120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return; 1429120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1430d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (SPACE_STATE_DOUBLE == spaceState) { 1431243e370fcb1c2cb8608614206075ecdbe79a6372Jean Chalard mHandler.cancelDoubleSpacesTimer(); 1432a32eb2721390d5964c83c787ad30fd3f61b936b0Jean Chalard if (mConnection.revertDoubleSpace()) { 1433d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // No need to reset mSpaceState, it has already be done (that's why we 1434d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // receive it as a parameter) 1435d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1436d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 1437d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 14382010aad741bc1a7266913bcb8b8348d6e401c95bJean Chalard if (mConnection.revertSwapPunctuation()) { 1439d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // Likewise 1440d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1441d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 14424733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 1443504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka 14444fef31510df542a3324426a6750950194d016086Jean Chalard // No cancelling of commit/double space/swap: we have a regular backspace. 14454fef31510df542a3324426a6750950194d016086Jean Chalard // We should backspace one char and restart suggestion if at the end of a word. 14464fef31510df542a3324426a6750950194d016086Jean Chalard if (mLastSelectionStart != mLastSelectionEnd) { 14474fef31510df542a3324426a6750950194d016086Jean Chalard // If there is a selection, remove it. 14484fef31510df542a3324426a6750950194d016086Jean Chalard final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; 14495475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); 14505475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(lengthToDelete, 0); 1451d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1452d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(lengthToDelete); 1453d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 14546558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } else { 14554fef31510df542a3324426a6750950194d016086Jean Chalard // There is no selection, just delete one character. 14564fef31510df542a3324426a6750950194d016086Jean Chalard if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { 14574fef31510df542a3324426a6750950194d016086Jean Chalard // This should never happen. 14584fef31510df542a3324426a6750950194d016086Jean Chalard Log.e(TAG, "Backspace when we don't know the selection position"); 14596558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 14604e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because 14614e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // we want to be able to compile against the Ice Cream Sandwich SDK. 14624e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard if (mTargetApplicationInfo != null 14634e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard && mTargetApplicationInfo.targetSdkVersion < 16) { 14644e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 14654e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 14664e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // reasons (there are race conditions with commits) but some applications are 14674e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // relying on this behavior so we continue to support it for older apps. 14685475b38328171a0841ae18074bd45380ec567e90Jean Chalard sendUpDownEnterOrBackspace(KeyEvent.KEYCODE_DEL); 14694e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } else { 14705475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 14714e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 1472d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1473d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(1); 1474d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 14754fef31510df542a3324426a6750950194d016086Jean Chalard if (mDeleteCount > DELETE_ACCELERATE_AT) { 14765475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1477d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1478d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(1); 1479d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1480edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1482fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { 14835475b38328171a0841ae18074bd45380ec567e90Jean Chalard restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); 14844fef31510df542a3324426a6750950194d016086Jean Chalard } 1485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1488e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard private boolean maybeStripSpace(final int code, 1489e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final int spaceState, final boolean isFromSuggestionStrip) { 1490e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1491bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1492e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1493e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else if ((SPACE_STATE_WEAK == spaceState 1494e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard || SPACE_STATE_SWAP_PUNCTUATION == spaceState) 1495e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard && isFromSuggestionStrip) { 1496297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWeakSpaceSwapper(code)) { 1497e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return true; 1498e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1499297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWeakSpaceStripper(code)) { 1500bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1501e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1502e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1503e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1504e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1505e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1506e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1507e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1508e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1509ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void handleCharacter(final int primaryCode, final int x, 1510120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int y, final int spaceState) { 1511196d82cdd740580ed79d801483dbc282be85d076Jean Chalard boolean isComposingWord = mWordComposer.isComposingWord(); 1512fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1513fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1514297e6d590bd957577c335aa8713a786145a70288Jean Chalard !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) { 1515fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (isComposingWord) { 1516fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Sanity check 1517fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard throw new RuntimeException("Should not be composing here"); 1518fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 15197a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 1520fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1521fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1522d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several 1523d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI 1524d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // thread here. 1525d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard if (!isComposingWord && (isAlphabet(primaryCode) 1526297e6d590bd957577c335aa8713a786145a70288Jean Chalard || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) 1527fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) && 1528297e6d590bd957577c335aa8713a786145a70288Jean Chalard !mConnection.isCursorTouchingWord(mCurrentSettings)) { 1529736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Reset entirely the composing state anyway, then start composing a new word unless 1530736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // the character is a single quote. The idea here is, single quote is not a 1531736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // separator and it should be treated as a normal character, except in the first 1532736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // position where it should not start composing a word. 1533736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode); 1534736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Here we don't need to reset the last composed word. It will be reset 1535736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // when we commit this one, if we ever do; if on the other hand we backspace 1536736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // it entirely and resume suggestions on the previous word, we'd like to still 1537736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // have touch coordinates for it. 1538736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard resetComposingState(false /* alsoResetLastComposedWord */); 1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15407b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (isComposingWord) { 15415c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka final int keyX, keyY; 15425c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka if (KeyboardActionListener.Adapter.isInvalidCoordinate(x) 15435c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka || KeyboardActionListener.Adapter.isInvalidCoordinate(y)) { 15445c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyX = x; 15455c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyY = y; 15465c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka } else { 15475c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka final KeyDetector keyDetector = 15485c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka mKeyboardSwitcher.getKeyboardView().getKeyDetector(); 15495c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyX = keyDetector.getTouchX(x); 15505c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyY = keyDetector.getTouchY(y); 15515c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka } 15525c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka mWordComposer.add(primaryCode, keyX, keyY); 15535475b38328171a0841ae18074bd45380ec567e90Jean Chalard // If it's the first letter, make note of auto-caps state 15545475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (mWordComposer.size() == 1) { 15555475b38328171a0841ae18074bd45380ec567e90Jean Chalard mWordComposer.setAutoCapitalized( 15565475b38328171a0841ae18074bd45380ec567e90Jean Chalard getCurrentAutoCapsState() != Constants.TextUtils.CAP_MODE_OFF); 1557923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15585475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1560e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, 1561e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); 1562863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 15637a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 1564e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1565e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (swapWeakSpace) { 1566bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 1567e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard mSpaceState = SPACE_STATE_WEAK; 1568e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 15698f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // In case the "add to dictionary" hint was still displayed. 15704702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint(); 1571e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1572a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 1573e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard Utils.Stats.onNonSeparator((char)primaryCode, x, y); 1574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1576c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard // Returns true if we did an autocorrection, false otherwise. 1577c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard private boolean handleSeparator(final int primaryCode, final int x, final int y, 1578120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState) { 1579c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1580923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Handle separator 1581196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 1582923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In certain languages where single quote is a separator, it's better 1583a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker // not to auto correct, but accept the typed word. For instance, 1584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // in Italian dov' should not be expanded to dove' because the elision 1585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // requires the last vowel to be removed. 1586ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard if (mCurrentSettings.mCorrectionEnabled && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { 15875475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitCurrentAutoCorrection(primaryCode); 1588c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = true; 1589923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 15905475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(primaryCode); 1591923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1592923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15934ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1594e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, spaceState, 1595e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); 1596863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 159700ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1598297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { 159900ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard sendKeyCodePoint(Keyboard.CODE_SPACE); 160000ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard } 16017a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 160289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 160389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (Keyboard.CODE_SPACE == primaryCode) { 1604fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { 1605bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard if (maybeDoubleSpace()) { 1606120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_DOUBLE; 1607120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else if (!isShowingPunctuationList()) { 1608120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_WEAK; 1609120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1610126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 1611120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1612120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mHandler.startDoubleSpacesTimer(); 1613297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mConnection.isCursorTouchingWord(mCurrentSettings)) { 1614a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 161589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 161689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1617fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (swapWeakSpace) { 1618bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 16194721427c7de3600f6fe7dfff16508a6a974fb3e4Jean Chalard mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; 1620fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else if (SPACE_STATE_PHANTOM == spaceState) { 1621fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // If we are in phantom space state, and the user presses a separator, we want to 1622fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // stay in phantom space state so that the next keypress has a chance to add the 1623fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // space. For example, if I type "Good dat", pick "day" from the suggestion strip 1624fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // then insert a comma and go on to typing the next word, I want the space to be 1625fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // inserted automatically before the next word, the same way it is when I don't 1626fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // input the comma. 1627fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1628120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1629120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 163089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Set punctuation right away. onUpdateSelection will fire but tests whether it is 163189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // already displayed or not, so it's okay. 163255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka setPunctuationSuggestions(); 1633923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1634120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1635406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)primaryCode, x, y); 1636120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1637c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard return didAutoCorrect; 1638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1639466741d8a78965b8509bf527344f289e50873092Mike LeBeau 164077d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard private CharSequence getTextWithUnderline(final CharSequence text) { 16410a59ac2ba88ac1f99151d9336136bc6fe7d416c0Jean Chalard return mIsAutoCorrectionIndicatorOn 164277d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) 1643fda847a870829f1491cbd5325f9c985213081149Jean Chalard : text; 164477d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 164577d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard 1646923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void handleClose() { 16475475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 1648923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestHideSelf(0); 1649c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka MainKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 16501679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka if (inputView != null) 16511679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka inputView.closing(); 1652923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1654a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // TODO: make this private 1655a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Outside LatinIME, only used by the test suite. 1656a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard /* package for tests */ boolean isShowingPunctuationList() { 16574702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView == null) return false; 16584702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka return mCurrentSettings.mSuggestPuncList == mSuggestionStripView.getSuggestions(); 16597599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16607599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1661a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private boolean isSuggestionsStripVisible() { 16624702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView == null) 1663b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa return false; 16644702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView.isShowingAddToDictionaryHint()) 16659fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16663d44f489b321f7586af4af8f281550a45653f50aJean Chalard if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation)) 16679fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return false; 1668dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()) 16699fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 1670fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation); 1671923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1673259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka private void clearSuggestionStrip() { 1674259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(SuggestedWords.EMPTY, false); 16757204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1676466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1677466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1678259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka private void setSuggestionStrip(final SuggestedWords words, final boolean isAutoCorrection) { 16794702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) { 16804702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.setSuggestions(words); 1681dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection); 1682466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1683d02783cb63293507e8544ea60d07559092ce83d4Jean Chalard } 1684ec780e2868962bf17f0dfd35d36895f543bde40asatok 168538e535e59676ac4d7bf27026fe3e16fcd9eb292eJean Chalard private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { 1686ec780e2868962bf17f0dfd35d36895f543bde40asatok // Put a blue underline to a word in TextView which will be auto-corrected. 16872be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator 16882be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard && mWordComposer.isComposingWord()) { 16892be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; 16902be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard final CharSequence textWithUnderline = 16912be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard getTextWithUnderline(mWordComposer.getTypedWord()); 16925475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(textWithUnderline, 1); 1693ec780e2868962bf17f0dfd35d36895f543bde40asatok } 1694466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1695466741d8a78965b8509bf527344f289e50873092Mike LeBeau 16967575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka private void updateSuggestionStrip() { 1697d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 1698305326e789c3a89517855cc5a023ed1aa3074dc0Jean Chalard 1699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Check if we have a suggestion engine attached. 17007ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { 1701edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard if (mWordComposer.isComposingWord()) { 17027ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " 17037ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard + "requested!"); 1704edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 1705edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 17067575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return; 1707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1708466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1709e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) { 1710e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard setPunctuationSuggestions(); 17117575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return; 1712e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard } 1713e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard 17147575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWords(); 17157575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 17167575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka showSuggestionStrip(suggestedWords, typedWord); 17177575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka } 17187575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka 17197575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka private SuggestedWords getSuggestedWords() { 17207575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 172132f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // Get the word on which we should search the bigrams. If we are composing a word, it's 172232f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we 172332f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // should just skip whitespace if any, so 1. 172432f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // TODO: this is slow (2-way IPC) - we should probably cache this instead. 172532f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard final CharSequence prevWord = 172632f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 172732f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard mWordComposer.isComposingWord() ? 2 : 1); 17287575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, 172932f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), 17305e573a1f0a63c017c7b0e4c4314235bd87c9363cJean Chalard mCurrentSettings.mCorrectionEnabled); 17317575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return maybeRetrieveOlderSuggestions(typedWord, suggestedWords); 17327ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard } 1733979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 173432f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord, 173532f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard final SuggestedWords suggestedWords) { 173632f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // TODO: consolidate this into getSuggestedWords 173709fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // We update the suggestion strip only when we have some suggestions to show, i.e. when 173809fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // the suggestion count is > 1; else, we leave the old suggestions, with the typed word 173909fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // replaced with the new one. However, when the word is a dictionary word, or when the 174009fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // length of the typed word is 1 or 0 (after a deletion typically), we do want to remove the 174109fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // old suggestions. Also, if we are showing the "add to dictionary" hint, we need to 174209fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // revert to suggestions - although it is unclear how we can come here if it's displayed. 174309fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard if (suggestedWords.size() > 1 || typedWord.length() <= 1 1744f4267c052160d8865399a758ce9d60916ed783ecJean Chalard || !suggestedWords.mTypedWordValid 17454702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka || mSuggestionStripView.isShowingAddToDictionaryHint()) { 1746ea80794dd43d44fe53884b4b8f4567af3d0e8331Jean Chalard return suggestedWords; 1747838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard } else { 17484702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka SuggestedWords previousSuggestions = mSuggestionStripView.getSuggestions(); 1749297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (previousSuggestions == mCurrentSettings.mSuggestPuncList) { 1750838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard previousSuggestions = SuggestedWords.EMPTY; 1751fe1a6d961cf039357f061482461e4d2e951ad346satok } 17524ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = 175388bf1ba5263f5a5c1df367ddc401db4109ef8677Jean Chalard SuggestedWords.getTypedWordAndPreviousSuggestions( 17544ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard typedWord, previousSuggestions); 1755ea80794dd43d44fe53884b4b8f4567af3d0e8331Jean Chalard return new SuggestedWords(typedWordAndPreviousSuggestions, 17562e2519ee914d4bf9462950553840557a4c19faedJean Chalard false /* typedWordValid */, 1757bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard false /* hasAutoCorrectionCandidate */, 175803a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isPunctuationSuggestions */, 17590142b997bf18f5d07e83b3fd403f0b3ea4736040satok true /* isObsoleteSuggestions */, 17600142b997bf18f5d07e83b3fd403f0b3ea4736040satok false /* isPrediction */); 17619fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka } 1762979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 17634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 1764259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka private void showSuggestionStrip(final SuggestedWords suggestedWords, 17657ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard final CharSequence typedWord) { 17662c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard if (null == suggestedWords || suggestedWords.size() <= 0) { 1767259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 17682c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard return; 17692c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard } 1770d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard final CharSequence autoCorrection; 17717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestedWords.size() > 0) { 1772aba432bf8d27cb9709f0410ca8ca234c6065567aJean Chalard if (suggestedWords.mWillAutoCorrect) { 1773d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = suggestedWords.getWord(1); 1774923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1775d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = typedWord; 1776923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1777923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1778d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = null; 1779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1780d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard mWordComposer.setAutoCorrection(autoCorrection); 17819b01890254c62a30b079bd9f79a30f9541faf11bJean Chalard final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); 1782259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(suggestedWords, isAutoCorrection); 1783dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 1784913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1785923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1786923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17875475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void commitCurrentAutoCorrection(final int separatorCodePoint) { 1788913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Complete any pending suggestions query first 1789d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka if (mHandler.hasPendingUpdateSuggestions()) { 1790259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka updateSuggestionStrip(); 1791923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1792eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final CharSequence typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); 1793eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final String typedWord = mWordComposer.getTypedWord(); 1794eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final CharSequence autoCorrection = (typedAutoCorrection != null) 1795eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang ? typedAutoCorrection : typedWord; 1796117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard if (autoCorrection != null) { 179746798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard if (TextUtils.isEmpty(typedWord)) { 179846798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard throw new RuntimeException("We have an auto-correction but the typed word " 179946798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard + "is empty? Impossible! I must commit suicide."); 180046798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard } 1801f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); 180260adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1803d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_commitCurrentAutoCorrection(typedWord, 180460adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge autoCorrection.toString()); 180560adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge } 18064733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 180766bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, 180866bb563535dbe3672f99f75bd71763a551444867Jean Chalard separatorCodePoint); 18095475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!typedWord.equals(autoCorrection)) { 18101c6cf26c3705e845418a29718c034598b52293ccJean Chalard // This will make the correction flash for a short while as a visual clue 18111c6cf26c3705e845418a29718c034598b52293ccJean Chalard // to the user that auto-correction happened. 18125475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCorrection( 18135475b38328171a0841ae18074bd45380ec567e90Jean Chalard new CorrectionInfo(mLastSelectionEnd - typedWord.length(), 181496fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasa typedWord, autoCorrection)); 18151c6cf26c3705e845418a29718c034598b52293ccJean Chalard } 1816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 18194702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} 18204702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // interface 1821c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 18229bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge public void pickSuggestionManually(final int index, final CharSequence suggestion, 18239d71748ba48dbc8793f3e1ecddf5fd31b8e59613Jean Chalard final int x, final int y) { 18244702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); 1825551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput 1826551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard if (suggestion.length() == 1 && isShowingPunctuationList()) { 1827551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Word separators are suggested before the user inputs something. 1828551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // So, LatinImeLogger logs "" as a user's input. 1829551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); 1830551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. 1831551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 1832551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard ResearchLogger.latinIME_punctuationSuggestion(index, suggestion, x, y); 1833551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard } 1834551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard final int primaryCode = suggestion.charAt(0); 1835551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard onCodeInput(primaryCode, 1836551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, 1837551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); 1838551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard return; 1839551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard } 1840551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard 18414fde56b8182514bcae64d76488724d2a64a73f14Jean Chalard mConnection.beginBatchEdit(); 1842eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0 1843eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // In the batch input mode, a manually picked suggested word should just replace 1844eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // the current batch input text and there is no need for a phantom space. 1845eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang && !mWordComposer.isBatchMode()) { 1846845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard int firstChar = Character.codePointAt(suggestion, 0); 1847297e6d590bd957577c335aa8713a786145a70288Jean Chalard if ((!mCurrentSettings.isWeakSpaceStripper(firstChar)) 1848297e6d590bd957577c335aa8713a786145a70288Jean Chalard && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) { 1849845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard sendKeyCodePoint(Keyboard.CODE_SPACE); 1850845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 1851845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 1852845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard 1853dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (mCurrentSettings.isApplicationSpecifiedCompletionsOn() 1854dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mApplicationSpecifiedCompletions != null 18551b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka && index >= 0 && index < mApplicationSpecifiedCompletions.length) { 18564702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) { 18574702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.clear(); 1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1859b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1860611a5bdf650f7bc54bf40176f84f1cd9c87aa9aaJean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 18615475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; 18625475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCompletion(completionInfo); 18639d71748ba48dbc8793f3e1ecddf5fd31b8e59613Jean Chalard mConnection.endBatchEdit(); 18645475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 18655475b38328171a0841ae18074bd45380ec567e90Jean Chalard ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index, 18665475b38328171a0841ae18074bd45380ec567e90Jean Chalard completionInfo.getText(), x, y); 18679a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 1868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 18706a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1871af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // We need to log before we commit, because the word composer will store away the user 1872af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // typed word. 18739bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge final String replacedWord = mWordComposer.getTypedWord().toString(); 18749bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge LatinImeLogger.logOnManualSuggestion(replacedWord, 18758cc8f26adfe0f06cebc697dac43a856326cf7afcTadashi G. Takaoka suggestion.toString(), index, suggestedWords); 18769bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 18779bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion, x, y); 18789bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge } 18794733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 188066bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, 188166bb563535dbe3672f99f75bd71763a551444867Jean Chalard LastComposedWord.NOT_A_SEPARATOR); 18824fde56b8182514bcae64d76488724d2a64a73f14Jean Chalard mConnection.endBatchEdit(); 188329a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard // Don't allow cancellation of manual pick 188429a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard mLastComposedWord.deactivate(); 1885fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1886fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // TODO: is this necessary? 1887fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mKeyboardSwitcher.updateShiftState(); 1888979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1889c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // We should show the "Touch again to save" hint if the user pressed the first entry 1890c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND either: 18917f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is no dictionary (we know that because we tried to load it => null != mSuggest 1892c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND mSuggest.hasMainDictionary() is false) 18937f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is a dictionary and the word is not in it 18947f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // Please note that if mSuggest is null, it means that everything is off: suggestion 18957f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // and correction, so we shouldn't try to show the hint 1896bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null 1897bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If there is no dictionary the hint should be shown. 1898c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa && (!mSuggest.hasMainDictionary() 1899bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If "suggestion" is not in the dictionary, the hint should be shown. 1900bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok || !AutoCorrection.isValidWord( 1901bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok mSuggest.getUnigramDictionaries(), suggestion, true)); 1902b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 1903406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE, 1904406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard WordComposer.NOT_A_COORDINATE); 1905b1dc8ad5f244337f91fcdac2a17078f5b9239cb7Jean Chalard if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { 19064702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.showAddToDictionaryHint( 19074702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka suggestion, mCurrentSettings.mHintToSaveText); 1908b1dc8ad5f244337f91fcdac2a17078f5b9239cb7Jean Chalard } else { 19098f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // If we're not showing the "Touch again to save", then update the suggestion strip. 1910a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 191166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 1912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1913a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1914979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 19158558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa * Commits the chosen word to the text field and saves it for later retrieval. 1916979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 1917c54d558e2e70bdfb2c1078cae7b88440d421dc67satok private void commitChosenWord(final CharSequence chosenWord, final int commitType, 191866bb563535dbe3672f99f75bd71763a551444867Jean Chalard final int separatorCode) { 19194702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); 1920e8bb8351d6f09f461851af619cabe5fcd2f66c0aJean Chalard mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( 1921e8bb8351d6f09f461851af619cabe5fcd2f66c0aJean Chalard this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); 1922140adf204bdf68e25a760b371516e23f6ac51cf2Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 1923140adf204bdf68e25a760b371516e23f6ac51cf2Jean Chalard ResearchLogger.latinIME_commitText(chosenWord); 1924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1925c54d558e2e70bdfb2c1078cae7b88440d421dc67satok // Add the word to the user history dictionary 1926c54d558e2e70bdfb2c1078cae7b88440d421dc67satok final CharSequence prevWord = addToUserHistoryDictionary(chosenWord); 19270fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // TODO: figure out here if this is an auto-correct or if the best word is actually 19280fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // what user typed. Note: currently this is done much later in 1929bdf89ce5feedb03e67b43f530b1eb9bd44203c63Jean Chalard // LastComposedWord#didCommitTypedWord by string equality of the remembered 19300fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // strings. 1931c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), 1932c54d558e2e70bdfb2c1078cae7b88440d421dc67satok separatorCode, prevWord); 1933923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1934923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1935a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private void setPunctuationSuggestions() { 1936a19c5e63804e6cffac5771b9749aad6c441e5e21Jean Chalard if (mCurrentSettings.mBigramPredictionEnabled) { 1937259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 1938d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard } else { 1939259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); 1940d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard } 19417204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1942913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 19436a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 19446a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1945c54d558e2e70bdfb2c1078cae7b88440d421dc67satok private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) { 1946c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (TextUtils.isEmpty(suggestion)) return null; 1947bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 1948ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // If correction is not enabled, we don't add words to the user history dictionary. 1949ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // That's to avoid unintended additions in some sensitive fields, or fields that 1950ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // expect to receive non-words. 1951ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard if (!mCurrentSettings.mCorrectionEnabled) return null; 1952bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 195367b9337b6cc478973d2c628fb5686583ce339bf0Satoshi Kataoka final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; 195467b9337b6cc478973d2c628fb5686583ce339bf0Satoshi Kataoka if (userHistoryDictionary != null) { 195502308bec632a5df23325c916bffec5def16b22b4Jean Chalard final CharSequence prevWord 1956d579f1aefc8d02254db297ffd6d8f9dbdcab0637Jean Chalard = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2); 195771f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard final String secondWord; 195871f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) { 19596a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka secondWord = suggestion.toString().toLowerCase( 19606a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSubtypeSwitcher.getCurrentSubtypeLocale()); 196171f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } else { 196271f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard secondWord = suggestion.toString(); 196371f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } 196468c650fb2a3b26d4000e849f96f0664598c95470Satoshi Kataoka // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". 196568c650fb2a3b26d4000e849f96f0664598c95470Satoshi Kataoka // We don't add words with 0-frequency (assuming they would be profanity etc.). 1966c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka final int maxFreq = AutoCorrection.getMaxFrequency( 1967c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka mSuggest.getUnigramDictionaries(), suggestion); 196868c650fb2a3b26d4000e849f96f0664598c95470Satoshi Kataoka if (maxFreq == 0) return null; 196967b9337b6cc478973d2c628fb5686583ce339bf0Satoshi Kataoka userHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(), 1970c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka secondWord, maxFreq > 0); 1971c54d558e2e70bdfb2c1078cae7b88440d421dc67satok return prevWord; 197232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 1973c54d558e2e70bdfb2c1078cae7b88440d421dc67satok return null; 197432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 197532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani 19766b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 19776b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Check if the cursor is actually at the end of a word. If so, restart suggestions on this 19786b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * word, else do nothing. 19796b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 19805475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() { 1981747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings); 1982747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard if (null != word) { 1983747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard restartSuggestionsOnWordBeforeCursor(word); 1984fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard } 19856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 19866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 19875475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursor(final CharSequence word) { 19883708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); 1989d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int length = word.length(); 19905475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(length, 0); 1991d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1992d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(length); 1993d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 19945475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(word, 1); 1995a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 19966b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 19976b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 19985475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void revertCommit() { 1999c54d558e2e70bdfb2c1078cae7b88440d421dc67satok final CharSequence previousWord = mLastComposedWord.mPrevWord; 2000b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard final String originallyTypedWord = mLastComposedWord.mTypedWord; 2001cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final CharSequence committedWord = mLastComposedWord.mCommittedWord; 2002cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final int cancelLength = committedWord.length(); 2003ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok final int separatorLength = LastComposedWord.getSeparatorLength( 2004193d23f40e1556074f323b7bd9695759f4798efeJean Chalard mLastComposedWord.mSeparatorCode); 2005193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // TODO: should we check our saved separator against the actual contents of the text view? 2006d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int deleteLength = cancelLength + separatorLength; 2007890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2008b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard if (mWordComposer.isComposingWord()) { 20095935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit, but we are composing a word"); 2010b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard } 2011890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard final String wordBeforeCursor = 20125475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.getTextBeforeCursor(deleteLength, 0) 2013193d23f40e1556074f323b7bd9695759f4798efeJean Chalard .subSequence(0, cancelLength).toString(); 2014cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard if (!TextUtils.equals(committedWord, wordBeforeCursor)) { 20155935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit check failed: we thought we were " 2016cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard + "reverting \"" + committedWord 2017890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); 2018890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 20198558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa } 20205475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(deleteLength, 0); 2021d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 2022d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge ResearchLogger.latinIME_deleteSurroundingText(deleteLength); 2023d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 2024c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { 2025c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mUserHistoryDictionary.cancelAddingUserHistory( 2026c54d558e2e70bdfb2c1078cae7b88440d421dc67satok previousWord.toString(), committedWord.toString()); 2027c54d558e2e70bdfb2c1078cae7b88440d421dc67satok } 20280e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard mConnection.commitText(originallyTypedWord, 1); 20290e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // Re-insert the separator 20300e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard sendKeyCodePoint(mLastComposedWord.mSeparatorCode); 20310e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode, WordComposer.NOT_A_COORDINATE, 20320e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard WordComposer.NOT_A_COORDINATE); 20330e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 20340e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard ResearchLogger.latinIME_revertCommit(originallyTypedWord); 2035193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } 20360e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // Don't restart suggestion yet. We'll restart if the user deletes the 20370e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // separator. 2038b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 2039746e014eb54f0d6278b948868dff4863bfe85ad8Jean Chalard // We have a separator between the word and the cursor: we should show predictions. 2040a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 2041890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2042890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 2043a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Used by the RingCharBuffer 2044923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean isWordSeparator(int code) { 2045297e6d590bd957577c335aa8713a786145a70288Jean Chalard return mCurrentSettings.isWordSeparator(code); 2046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2047923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 204888fc9d44186120f9edc5cf7ec0e2af85260fed04satok // Notify that language or mode have been changed and toggleLanguage will update KeyboardID 2049a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // according to new language or mode. Called from SubtypeSwitcher. 2050c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka public void onRefreshKeyboard() { 20511e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // When the device locale is changed in SetupWizard etc., this method may get called via 20521e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // onConfigurationChanged before SoftInputWindow is shown. 20531e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka if (mKeyboardSwitcher.getKeyboardView() != null) { 20541e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // Reload keyboard because the current language has been changed. 2055297e6d590bd957577c335aa8713a786145a70288Jean Chalard mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings); 20561e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka } 20570ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 205817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 2059b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // Since we just changed languages, we should re-evaluate suggestions with whatever word 2060b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // we are currently composing. If we are not composing anything, we may want to display 20618f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway). 2062a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 206336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 206436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 206578e3977e90a9946a057dfb628f99683e386015bdTadashi G. Takaoka // TODO: Remove this method from {@link LatinIME} and move {@link FeedbackManager} to 2066a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // {@link KeyboardSwitcher}. Called from KeyboardSwitcher 2067564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard public void hapticAndAudioFeedback(final int primaryCode) { 2068544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard mFeedbackManager.hapticAndAudioFeedback(primaryCode, mKeyboardSwitcher.getKeyboardView()); 2069d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka } 2070d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka 2071a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback called by PointerTracker through the KeyboardActionListener. This is called when a 2072a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // key is depressed; release matching call is onReleaseKey below. 20735a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 20742a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onPressKey(int primaryCode) { 2075a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mKeyboardSwitcher.onPressKey(primaryCode); 2076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2078a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback by PointerTracker through the KeyboardActionListener. This is called when a key 2079a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // is released; press matching call is onPressKey above. 20805a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 20812a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onReleaseKey(int primaryCode, boolean withSliding) { 20822a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); 20838d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 20848d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv // If accessibility is on, ensure the user receives keyboard state updates. 20858d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 20868d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (primaryCode) { 20878d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case Keyboard.CODE_SHIFT: 20888d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); 20898d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 20908d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 20918d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); 20928d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 20938d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 20948d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2095978c96aa995015658070346b60826a3a34fdaf84Jean Chalard 2096978c96aa995015658070346b60826a3a34fdaf84Jean Chalard if (Keyboard.CODE_DELETE == primaryCode) { 2097978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // This is a stopgap solution to avoid leaving a high surrogate alone in a text view. 2098978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // In the future, we need to deprecate deteleSurroundingText() and have a surrogate 2099978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // pair-friendly way of deleting characters in InputConnection. 21005475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastChar = mConnection.getTextBeforeCursor(1, 0); 21015475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) { 21025475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 2103978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2104978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2106a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2107123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka // receive ringer mode change and network state change. 2108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private BroadcastReceiver mReceiver = new BroadcastReceiver() { 2109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 2110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onReceive(Context context, Intent intent) { 2111123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final String action = intent.getAction(); 2112564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2113123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka mSubtypeSwitcher.onNetworkStateChanged(intent); 211421af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 211521af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard mFeedbackManager.onRingerModeChanged(); 2116123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } 2117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 2119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2120c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka private void launchSettings() { 21213c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge handleClose(); 21223c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(SettingsActivity.class); 2123466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2124466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2125a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from debug code only 2126bf96661d33d0126adb60a48880ceba1ff055d4a4satok public void launchDebugSettings() { 21273c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge handleClose(); 21283c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(DebugSettingsActivity.class); 2129bf96661d33d0126adb60a48880ceba1ff055d4a4satok } 2130bf96661d33d0126adb60a48880ceba1ff055d4a4satok 21313c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge public void launchKeyboardedDialogActivity(Class<? extends Activity> activityClass) { 21323c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge // Put the text in the attached EditText into a safe, saved state before switching to a 21333c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge // new activity that will also use the soft keyboard. 21343c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge commitTyped(LastComposedWord.NOT_A_SEPARATOR); 21353c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(activityClass); 21363c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge } 21373c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge 21383c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge private void launchSubActivity(Class<? extends Activity> activityClass) { 2139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Intent intent = new Intent(); 21403c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge intent.setClass(LatinIME.this, activityClass); 2141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project startActivity(intent); 2143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 21452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showSubtypeSelectorAndSettings() { 214685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 214785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 214885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka // TODO: Should use new string "Select active input modes". 214985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.language_selection_title), 215085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.english_ime_settings), 215185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 215255d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka final Context context = this; 215385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 21542fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka @Override 21552fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka public void onClick(DialogInterface di, int position) { 21562fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka di.dismiss(); 21572fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka switch (position) { 215885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 21592cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok Intent intent = CompatUtils.getInputLanguageSelectionIntent( 216055d28fd1b2631a63542a647f693d8a8ed749bcf7Tadashi G. Takaoka ImfUtils.getInputMethodIdOfThisIme(context), 21612a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Intent.FLAG_ACTIVITY_NEW_TASK 21622fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 21632fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 21642fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka startActivity(intent); 21652fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2166aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa case 1: 2167aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa launchSettings(); 2168aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa break; 21692fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 21702fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 217185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2172bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2173bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2174bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2175724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge showOptionDialog(builder.create()); 21762fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 2177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 21786b966160ac8570271547bf63217efa5e228d4accKurt Partridge public void showOptionDialog(AlertDialog dialog) { 21796a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken(); 218013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka if (windowToken == null) return; 218113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 218213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCancelable(true); 218313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCanceledOnTouchOutside(true); 218413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 218513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final Window window = dialog.getWindow(); 218613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final WindowManager.LayoutParams lp = window.getAttributes(); 218713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.token = windowToken; 218813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 218913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.setAttributes(lp); 219013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 219113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 219213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka mOptionsDialog = dialog; 219313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.show(); 219413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka } 219513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 21967e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 21977e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 2198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.dump(fd, fout, args); 2199a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project final Printer p = new PrintWriterPrinter(fout); 2201923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println("LatinIME state :"); 22023708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2203df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; 2204df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka p.println(" Keyboard mode = " + keyboardMode); 2205fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard p.println(" mIsSuggestionsSuggestionsRequested = " 2206fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)); 22072f3a694e29ad5a63052a2f963327855fee099f55Jean Chalard p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled); 22084d0f03bd66742ee292da81a3e025e119f28b6940Jean Chalard p.println(" isComposingWord=" + mWordComposer.isComposingWord()); 2209297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mSoundOn=" + mCurrentSettings.mSoundOn); 2210297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn); 2211297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn); 2212dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString()); 2213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 2215