LatinIME.java revision edbb65be3e5e391affbf47e134422ac1d1a4ae13
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; 39f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaokaimport android.os.Handler; 40f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaokaimport android.os.HandlerThread; 4181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaokaimport android.os.IBinder; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager; 45e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils; 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log; 48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter; 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer; 504e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyCharacterMap; 514e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyEvent; 52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 53c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.view.ViewGroup.LayoutParams; 5413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.Window; 5513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.WindowManager; 56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo; 5796fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasaimport android.view.inputmethod.CorrectionInfo; 58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo; 599cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 60c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 615ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils; 628d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 6315f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting; 64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils; 65fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasaimport com.android.inputmethod.compat.InputMethodServiceCompatUtils; 661fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils; 675c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector; 68c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 69c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 706b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 71c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 72f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 73c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView; 7416c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaokaimport com.android.inputmethod.latin.LocaleUtils.RunInLocale; 7587cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataokaimport com.android.inputmethod.latin.Utils.Stats; 76c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 774702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionStripView; 786b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 80466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor; 81466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter; 824ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalardimport java.util.ArrayList; 83466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale; 84466741d8a78965b8509bf527344f289e50873092Mike LeBeau 85923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 86923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard. 87923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 88a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class LatinIME extends InputMethodService implements KeyboardActionListener, 89369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka SuggestionStripView.Listener, TargetApplicationGetter.OnTargetApplicationKnownListener, 90369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka Suggest.SuggestInitializationListener { 918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka private static final String TAG = LatinIME.class.getSimpleName(); 92409220583333bdf06290dd9fd42f91b5c0d1b11asatok private static final boolean TRACE = false; 939e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka private static boolean DEBUG; 94a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 959e347d3d448e48229c46aad394ec9bd60cd5807bsatok private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; 96fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa 97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // How many continuous deletes at which to start deleting at a higher speed. 98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int DELETE_ACCELERATE_AT = 20; 99923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Key events coming any faster than this are long-presses. 100d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani private static final int QUICK_PRESS = 200; 101a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 10259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private static final int PENDING_IMS_CALLBACK_DURATION = 800; 103055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 104cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /** 105cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * The name of the scheme used by the Package Manager to warn of a new package installation, 106cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * replacement or removal. 107cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard */ 108cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private static final String SCHEME_PACKAGE = "package"; 109cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 110fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_NONE = 0; 111120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Double space: the state where the user pressed space twice quickly, which LatinIME 112120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // resolved as period-space. Undoing this converts the period to a space. 113fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_DOUBLE = 1; 114b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip 115b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // have just been swapped. Undoing this swaps them back; the space is still considered weak. 116120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; 117fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak 118fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // spaces happen when the user presses space, accepting the current suggestion (whether 119fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // it's an auto-correction or not). 120fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_WEAK = 3; 121fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom space: a not-yet-inserted space that should get inserted on the next input, 122fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // character provided it's not a separator. If it's a separator, the phantom space is dropped. 123fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom spaces happen when a user chooses a word from the suggestion strip. 124fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_PHANTOM = 4; 125120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 126120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Current space state of the input method. This can be any of the above constants. 127120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private int mSpaceState; 128126698fdd256a2e3734634d3b923cabd800064baJean Chalard 129297e6d590bd957577c335aa8713a786145a70288Jean Chalard private SettingsValues mCurrentSettings; 13017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 131d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka private View mExtractArea; 132abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka private View mKeyPreviewBackingView; 133913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private View mSuggestionsContainer; 1344702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka private SuggestionStripView mSuggestionStripView; 13515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting Suggest mSuggest; 1361b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private CompletionInfo[] mApplicationSpecifiedCompletions; 137b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard private ApplicationInfo mTargetApplicationInfo; 138a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1396fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private RichInputMethodManager mRichImm; 1402fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private Resources mResources; 1412fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private SharedPreferences mPrefs; 14215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; 14389ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard private final SubtypeSwitcher mSubtypeSwitcher; 1441931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka private final SubtypeState mSubtypeState = new SubtypeState(); 145a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1466a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka private boolean mIsMainDictionaryAvailable; 14767fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private UserBinaryDictionary mUserDictionary; 1489ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard private UserHistoryDictionary mUserHistoryDictionary; 14988562bec54658840dcce352127bdc15705c20a89Jean Chalard private boolean mIsUserDictionaryAvailable; 15036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 1512692a8700737d8eed268039aa27b22a31669da08Jean Chalard private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 15287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka private final WordComposer mWordComposer = new WordComposer(); 153f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard private RichInputConnection mConnection = new RichInputConnection(this); 154409220583333bdf06290dd9fd42f91b5c0d1b11asatok 155979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Keep track of the last selection range to decide if we need to show word alternatives 15677da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private static final int NOT_A_CURSOR_POSITION = -1; 15777da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionStart = NOT_A_CURSOR_POSITION; 15877da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; 159979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1604733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't 1614733609947c0ec74e460bd714fffca0518ade93aJean Chalard // "expect" it, it means the user actually moved the cursor. 1624733609947c0ec74e460bd714fffca0518ade93aJean Chalard private boolean mExpectingUpdateSelection; 163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mDeleteCount; 164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private long mLastKeyTime; 165a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 16638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Member variables for remembering the current device orientation. 16738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka private int mDisplayOrientation; 16838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 169cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Object for reacting to adding/removing a dictionary pack. 170710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa // TODO: The experimental version is not supported by the Dictionary Pack Service yet. 171cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private BroadcastReceiver mDictionaryPackInstallReceiver = 172710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa ProductionFlag.IS_EXPERIMENTAL 173710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa ? null : new DictionaryPackInstallBroadcastReceiver(this); 174cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 175dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Keeps track of most recently inserted text (multi-character key) for reverting 176bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String mEnteredText; 177dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 17870852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard private boolean mIsAutoCorrectionIndicatorOn; 179604d80c67185954d4691ac775be59c499eee3b1csatok 18013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka private AlertDialog mOptionsDialog; 18113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 182fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa private final boolean mIsHardwareAcceleratedDrawingEnabled; 183fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa 1844f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public final UIHandler mHandler = new UIHandler(this); 185d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 186a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka public static final class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { 18727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_UPDATE_SHIFT_STATE = 0; 18827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_PENDING_IMS_CALLBACK = 1; 18927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION_STRIP = 2; 190f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3; 191f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 192f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; 1934c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka 19410dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateSuggestions; 19510dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateShiftState; 1962b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private long mDoubleSpacePeriodTimeout; 1972b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private long mDoubleSpacePeriodTimerStart; 19838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 199f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public UIHandler(final LatinIME outerInstance) { 2004f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 20110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka } 202175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 20310dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka public void onCreate() { 20410dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka final Resources res = getOuterInstance().getResources(); 205175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateSuggestions = 206175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_suggestions); 207175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateShiftState = 208175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_shift_state); 2092b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mDoubleSpacePeriodTimeout = 2102b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa res.getInteger(R.integer.config_double_space_period_timeout); 2114f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 2124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 214f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void handleMessage(final Message msg) { 2154f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 2164f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; 217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 218dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard case MSG_UPDATE_SUGGESTION_STRIP: 219259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka latinIme.updateSuggestionStrip(); 220d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 221d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SHIFT_STATE: 222de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka switcher.updateShiftState(); 223d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 224f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka case MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: 225f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords)msg.obj, 226f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT); 227f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka break; 228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 230d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 231a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard public void postUpdateSuggestionStrip() { 232dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions); 233d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 234d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 235d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard public void cancelUpdateSuggestionStrip() { 236dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard removeMessages(MSG_UPDATE_SUGGESTION_STRIP); 237d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 238d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 239d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public boolean hasPendingUpdateSuggestions() { 240dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard return hasMessages(MSG_UPDATE_SUGGESTION_STRIP); 241d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 242d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 243beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void postUpdateShiftState() { 244d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 245175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); 246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 247d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 248d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateShiftState() { 249d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 250d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 251d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 252f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, 253f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final boolean dismissGestureFloatingPreviewText) { 254f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); 255f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final int arg1 = dismissGestureFloatingPreviewText 256f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT : 0; 257f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1, 0, suggestedWords) 258f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka .sendToTarget(); 259f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 260f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 2612b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa public void startDoubleSpacePeriodTimer() { 2622b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mDoubleSpacePeriodTimerStart = SystemClock.uptimeMillis(); 263fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 264fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 2652b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa public void cancelDoubleSpacePeriodTimer() { 2662b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mDoubleSpacePeriodTimerStart = 0; 267fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 268fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 2692b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa public boolean isAcceptingDoubleSpacePeriod() { 2702b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa return SystemClock.uptimeMillis() - mDoubleSpacePeriodTimerStart 2712b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa < mDoubleSpacePeriodTimeout; 272fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 27338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 27459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Working variables for the following methods. 27559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mIsOrientationChanging; 2765fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard private boolean mPendingSuccessiveImsCallback; 27759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingStartInput; 27859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInputView; 27959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInput; 280e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private EditorInfo mAppliedEditorInfo; 28159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 28259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void startOrientationChanging() { 283dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka removeMessages(MSG_PENDING_IMS_CALLBACK); 284dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka resetPendingImsCallback(); 28559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = true; 286055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 287f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka if (latinIme.isInputViewShown()) { 288f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka latinIme.mKeyboardSwitcher.saveKeyboardState(); 289f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka } 29059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 29159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 29259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void resetPendingImsCallback() { 29359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = false; 29459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = false; 29559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = false; 29659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 29759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 298f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void executePendingImsCallback(final LatinIME latinIme, final EditorInfo editorInfo, 29959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka boolean restarting) { 30059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInputView) 30159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(mHasPendingFinishInput); 30259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInput) 30359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 30459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingStartInput) 305e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 30659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka resetPendingImsCallback(); 30759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 30859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 309f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInput(final EditorInfo editorInfo, final boolean restarting) { 31059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 31159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the second onStartInput after orientation changed. 31259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = true; 31359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 31459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mIsOrientationChanging && restarting) { 31559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // This is the first onStartInput after orientation changed. 31659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = false; 3175fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = true; 31859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 31959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 320e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 321e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 322055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 323055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 324055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 325f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) { 3266b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK) 3276b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { 328e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // Typically this is the second onStartInputView after orientation changed. 329e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 330e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } else { 3315fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard if (mPendingSuccessiveImsCallback) { 332e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // This is the first onStartInputView after orientation changed. 3335fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = false; 334e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 335e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), 336e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka PENDING_IMS_CALLBACK_DURATION); 337e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 338e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 339e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 340e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputViewInternal(editorInfo, restarting); 341e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = editorInfo; 342e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 34359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 34459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 345f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onFinishInputView(final boolean finishingInput) { 34659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 34759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInputView after orientation changed. 34859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = true; 34959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 35059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 35159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(finishingInput); 352e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = null; 35338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 35438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 355ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka 35659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 35759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 35859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInput after orientation changed. 35959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = true; 36059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 36159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 36259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka executePendingImsCallback(latinIme, null, false); 36359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 364ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 365ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 36638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 36738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 3681931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka static final class SubtypeState { 3691931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka private InputMethodSubtype mLastActiveSubtype; 3701931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka private boolean mCurrentSubtypeUsed; 3711931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 3721931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka public void currentSubtypeUsed() { 3731931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mCurrentSubtypeUsed = true; 3741931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 3751931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 3761931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka public void switchSubtype(final IBinder token, final RichInputMethodManager richImm) { 3771931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka final InputMethodSubtype currentSubtype = richImm.getInputMethodManager() 3781931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka .getCurrentInputMethodSubtype(); 3791931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype; 3801931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka final boolean currentSubtypeUsed = mCurrentSubtypeUsed; 3811931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka if (currentSubtypeUsed) { 3821931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mLastActiveSubtype = currentSubtype; 3831931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mCurrentSubtypeUsed = false; 3841931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 3851931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka if (currentSubtypeUsed 3861931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka && richImm.checkIfSubtypeBelongsToThisImeAndEnabled(lastActiveSubtype) 3871931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka && !currentSubtype.equals(lastActiveSubtype)) { 3881931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka richImm.setInputMethodAndSubtype(token, lastActiveSubtype); 3891931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka return; 3901931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 3911931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka richImm.switchToNextInputMethod(token, true /* onlyCurrentIme */); 3921931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 3931931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 3941931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 39589ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard public LatinIME() { 39689ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard super(); 39789ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 39889ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mKeyboardSwitcher = KeyboardSwitcher.getInstance(); 399fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa mIsHardwareAcceleratedDrawingEnabled = 400fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa InputMethodServiceCompatUtils.enableHardwareAcceleration(this); 401fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled); 40289ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard } 40389ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard 4047e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 4057e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka public void onCreate() { 40685e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 40785e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka mResources = getResources(); 40885e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka 40985e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka LatinImeLogger.init(this, mPrefs); 410c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 41185e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka ResearchLogger.getInstance().init(this, mPrefs); 412c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa } 41385e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka RichInputMethodManager.init(this, mPrefs); 41485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka mRichImm = RichInputMethodManager.getInstance(); 415ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka SubtypeSwitcher.init(this); 41685e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka KeyboardSwitcher.init(this, mPrefs); 4172ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka AccessibilityUtils.init(this); 418363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onCreate(); 420363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 42110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka mHandler.onCreate(); 4229e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka DEBUG = LatinImeLogger.sDBG; 423363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 42428f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa loadSettings(); 4251f05cf6dab45c21d1ed334247929434d97c40584Tadashi G. Takaoka initSuggest(); 426979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 42785e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka mDisplayOrientation = mResources.getConfiguration().orientation; 428b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 429cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Register to receive ringer mode change and network state change. 430cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Also receive installation and removal of a dictionary pack. 431123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final IntentFilter filter = new IntentFilter(); 432123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 43321af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 434923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project registerReceiver(mReceiver, filter); 435cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 436710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa // TODO: The experimental version is not supported by the Dictionary Pack Service yet. 437710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa if (!ProductionFlag.IS_EXPERIMENTAL) { 438710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa final IntentFilter packageFilter = new IntentFilter(); 439710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 440710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 441710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa packageFilter.addDataScheme(SCHEME_PACKAGE); 442710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa registerReceiver(mDictionaryPackInstallReceiver, packageFilter); 443710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa 444710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa final IntentFilter newDictFilter = new IntentFilter(); 445710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa newDictFilter.addAction( 446710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION); 447710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); 448710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa } 449923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 45036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 45117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // Has to be package-visible for unit tests 45215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting 4539fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka void loadSettings() { 4544f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 4554f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 45617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 457b0561ae98063f83684706886490ba5670138fcccJean Chalard final InputAttributes inputAttributes = 458b0561ae98063f83684706886490ba5670138fcccJean Chalard new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode()); 45916c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { 46016c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka @Override 46116c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka protected SettingsValues job(Resources res) { 462b0561ae98063f83684706886490ba5670138fcccJean Chalard return new SettingsValues(mPrefs, inputAttributes, LatinIME.this); 46316c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka } 46416c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka }; 465297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings = job.runInLocale(mResources, mSubtypeSwitcher.getCurrentSubtypeLocale()); 46614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); 46717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 46817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 4698335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka // Note that this method is called from a non-UI thread. 470369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka @Override 471f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onUpdateMainDictionaryAvailability(final boolean isMainDictionaryAvailable) { 472369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka mIsMainDictionaryAvailable = isMainDictionaryAvailable; 4738335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 4748335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka if (mainKeyboardView != null) { 4758335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka mainKeyboardView.setMainDictionaryAvailability(isMainDictionaryAvailable); 4768335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka } 477369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka } 478369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka 4790ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private void initSuggest() { 4806a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 4816a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final String localeStr = subtypeLocale.toString(); 48236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 48367fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary oldContactsDictionary; 48478ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka if (mSuggest != null) { 48578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = mSuggest.getContactsDictionary(); 48678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.close(); 48778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } else { 48878ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = null; 48978ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 490369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka mSuggest = new Suggest(this /* Context */, subtypeLocale, 491369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka this /* SuggestInitializationListener */); 492ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard if (mCurrentSettings.mCorrectionEnabled) { 493297e6d590bd957577c335aa8713a786145a70288Jean Chalard mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); 49478ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 495e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 4966a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 4976080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 4986080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge ResearchLogger.getInstance().initSuggest(mSuggest); 4996080f6878b10916013a8a5e1d5f58f8041452c56Kurt Partridge } 5006a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka 50167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary = new UserBinaryDictionary(this, localeStr); 50267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); 50378ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserDictionary(mUserDictionary); 504e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 50578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka resetContactsDictionary(oldContactsDictionary); 506e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 5074f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 5084f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 5094f96bb4520de3610ae94da96b98e507ca7b76362satok if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 510b5afd3de0c20bce40a600357a15e8e8df0e62420Jean Chalard mUserHistoryDictionary = UserHistoryDictionary.getInstance(this, localeStr, mPrefs); 51178ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); 512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 51336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 51414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard /** 51514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * Resets the contacts dictionary in mSuggest according to the user settings. 51614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 5172e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * This method takes an optional contacts dictionary to use when the locale hasn't changed 5182e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang * since the contacts dictionary can be opened or closed as necessary depending on the settings. 51914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 52014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * @param oldContactsDictionary an optional dictionary to use, or null 52114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard */ 52267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard private void resetContactsDictionary(final ContactsBinaryDictionary oldContactsDictionary) { 523297e6d590bd957577c335aa8713a786145a70288Jean Chalard final boolean shouldSetDictionary = (null != mSuggest && mCurrentSettings.mUseContactsDict); 52414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 52567fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard final ContactsBinaryDictionary dictionaryToUse; 52614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (!shouldSetDictionary) { 52714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the dictionary is closed. If it is already closed, this is a no-op, 52814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // so it's safe to call it anyways. 52914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != oldContactsDictionary) oldContactsDictionary.close(); 53014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = null; 53114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 5322e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang final Locale locale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 5332e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang if (null != oldContactsDictionary) { 53467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard if (!oldContactsDictionary.mLocale.equals(locale)) { 53567fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // If the locale has changed then recreate the contacts dictionary. This 53667fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // allows locale dependent rules for handling bigram name predictions. 53767fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.close(); 53805efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, locale); 5392e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } else { 54067fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // Make sure the old contacts dictionary is opened. If it is already open, 54167fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard // this is a no-op, so it's safe to call it anyways. 54267fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard oldContactsDictionary.reopen(this); 5432e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang dictionaryToUse = oldContactsDictionary; 5442e8aa0600293875c620ba7b650010cb30ec023c1Tom Ouyang } 54518222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } else { 54605efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard dictionaryToUse = new ContactsBinaryDictionary(this, locale); 54718222f8c863e509538857b1fafca9c696fae2f55Tom Ouyang } 54814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 54914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 55014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != mSuggest) { 55114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard mSuggest.setContactsDictionary(dictionaryToUse); 55214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 553699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard } 554699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard 555cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /* package private */ void resetSuggestMainDict() { 5566a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale(); 55779eefda0d3ab5e03c2d012ed8ea1898004781871Tadashi G. Takaoka mSuggest.resetMainDict(this, subtypeLocale, this /* SuggestInitializationListener */); 5586a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mIsMainDictionaryAvailable = DictionaryFactory.isDictionaryAvailable(this, subtypeLocale); 559cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard } 560cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 561466741d8a78965b8509bf527344f289e50873092Mike LeBeau @Override 562466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onDestroy() { 563e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa if (mSuggest != null) { 564e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.close(); 565e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest = null; 566979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 567923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project unregisterReceiver(mReceiver); 568710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa // TODO: The experimental version is not supported by the Dictionary Pack Service yet. 569710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa if (!ProductionFlag.IS_EXPERIMENTAL) { 570710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa unregisterReceiver(mDictionaryPackInstallReceiver); 571710d06cea91a8e6bf04a27f0bcd88d76a5cc5acdKen Wakasa } 572979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 573979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.onDestroy(); 574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onDestroy(); 575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 576923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 577923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 578f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onConfigurationChanged(final Configuration conf) { 5799fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka // System locale has been changed. Needs to reload keyboard. 5806fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (mSubtypeSwitcher.onConfigurationChanged(conf)) { 5819fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka loadKeyboard(); 5829fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka } 583b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani // If orientation changed while predicting, commit the change 584f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka if (mDisplayOrientation != conf.orientation) { 585f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = conf.orientation; 586f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mHandler.startOrientationChanging(); 587f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 5885475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 5895475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.finishComposingText(); 5905475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 5910a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka if (isShowingOptionDialog()) { 5922fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka mOptionsDialog.dismiss(); 5930a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka } 594b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onConfigurationChanged(conf); 596923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 597b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public View onCreateInputView() { 600622d6a5b1b3d6a9140765b868abf1cdf412bc4f3Tadashi G. Takaoka return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled); 6016c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka } 6026c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka 6036c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka @Override 604f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void setInputView(final View view) { 6056c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka super.setInputView(view); 606d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka mExtractArea = getWindow().getWindow().getDecorView() 607d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka .findViewById(android.R.id.extractArea); 608abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); 609913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer = view.findViewById(R.id.suggestions_container); 6104702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view); 6114702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) 6124702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.setListener(this, view); 613f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka if (LatinImeLogger.sVISUALDEBUG) { 614f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); 615f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka } 616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 619f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void setCandidatesView(final View view) { 620c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka // To ensure that CandidatesView will never be set. 621c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return; 622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 623923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 624a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker @Override 625f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInput(final EditorInfo editorInfo, final boolean restarting) { 626e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInput(editorInfo, restarting); 62759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 62859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 62959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 630f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) { 631e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInputView(editorInfo, restarting); 63259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 63359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 63459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 635f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onFinishInputView(final boolean finishingInput) { 63659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInputView(finishingInput); 63759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 63838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 63959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 64059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 64159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInput(); 64259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 64359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 6449cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka @Override 645f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) { 6464f96bb4520de3610ae94da96b98e507ca7b76362satok // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged() 6474f96bb4520de3610ae94da96b98e507ca7b76362satok // is not guaranteed. It may even be called at the same time on a different thread. 6486a7019ff5db19b1e3f8d7afbba71af813cab9a37Tadashi G. Takaoka mSubtypeSwitcher.updateSubtype(subtype); 6499fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka loadKeyboard(); 6509cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka } 6519cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka 652f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) { 653e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInput(editorInfo, restarting); 65459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 65559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 6561cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka @SuppressWarnings("deprecation") 657f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restarting) { 658e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInputView(editorInfo, restarting); 65945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 66027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView(); 6618e09172df1bb176cc899940862c56bed9b9aec4esatok 662ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (editorInfo == null) { 663ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.e(TAG, "Null EditorInfo in onStartInputView()"); 664ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (LatinImeLogger.sDBG) { 665ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok throw new NullPointerException("Null EditorInfo in onStartInputView()"); 666ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 667ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok return; 668ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 66989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (DEBUG) { 670ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.d(TAG, "onStartInputView: editorInfo:" 671ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok + String.format("inputType=0x%08x imeOptions=0x%08x", 672ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok editorInfo.inputType, editorInfo.imeOptions)); 673b6fb5eb391987f3e426649a892cdcbf781957f5asatok Log.d(TAG, "All caps = " 674b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0) 675b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", sentence caps = " 676b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0) 677b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ", word caps = " 678b6fb5eb391987f3e426649a892cdcbf781957f5asatok + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); 679910b73127fa207dd26ec8124000262523b0aac0csatok } 6809bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 68148a7681e064ae259b840f0e757da2d716043d893Kurt Partridge ResearchLogger.latinIME_onStartInputViewInternal(editorInfo, mPrefs); 6829bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 6831cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) { 6844f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6854f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6861cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead"); 6874f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6881cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) { 6894f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6904f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6914f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); 6924f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6934f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka 6941b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard mTargetApplicationInfo = 6951b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard TargetApplicationGetter.getCachedApplicationInfo(editorInfo.packageName); 6961b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard if (null == mTargetApplicationInfo) { 6971b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard new TargetApplicationGetter(this /* context */, this /* listener */) 6981b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard .execute(editorInfo.packageName); 6991b1243d61fd682d804e61de6a1eccbf0e8ba78b2Jean Chalard } 700b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 7017ef235f53f2291f22ddf8c56be9860a218b25bbbTadashi G. Takaoka LatinImeLogger.onStartInputView(editorInfo); 702923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In landscape mode, this method gets called without the input view being created. 70327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView == null) { 704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 705923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 707b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette // Forward this event to the accessibility utilities, if enabled. 708b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); 709b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette if (accessUtils.isTouchExplorationEnabled()) { 71005384933097c1e9c35e8be5c03757d072e5ffa46alanv accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting); 711b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette } 712b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette 713e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard final boolean inputTypeChanged = !mCurrentSettings.isSameInputType(editorInfo); 714e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard final boolean isDifferentTextField = !restarting || inputTypeChanged; 715e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard if (isDifferentTextField) { 7169fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka final boolean currentSubtypeEnabled = mSubtypeSwitcher 7179fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka .updateParametersOnStartInputViewAndReturnIfCurrentSubtypeEnabled(); 7189fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka if (!currentSubtypeEnabled) { 7199fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka // Current subtype is disabled. Needs to update subtype and keyboard. 7206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final InputMethodSubtype newSubtype = mRichImm.getCurrentInputMethodSubtype( 7216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mSubtypeSwitcher.getNoLanguageSubtype()); 7229fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka mSubtypeSwitcher.updateSubtype(newSubtype); 7239fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka loadKeyboard(); 7249fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka } 725aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard } 7264ab730dbd34fad323063f2ffd31ce33de746668dsatok 727b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // The EditorInfo might have a flag that affects fullscreen mode. 728b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // Note: This call should be done by InputMethodService? 729b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka updateFullscreenMode(); 730ccc35f7fa74860a8d737a4e9ff01fc0168dd329dJean Chalard mApplicationSpecifiedCompletions = null; 731c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 73261cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // The app calling setText() has the effect of clearing the composing 73361cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // span, so we should reset our state unconditionally, even if restarting is true. 73461cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard mEnteredText = null; 73561cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 73661cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard mDeleteCount = 0; 73761cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard mSpaceState = SPACE_STATE_NONE; 73861cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard 73961cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard if (mSuggestionStripView != null) { 74061cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // This will set the punctuation suggestions if next word suggestion is off; 74161cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard // otherwise it will clear the suggestion strip. 74261cc2a33911ff2a8115ce727c8cac6d73d989c42Jean Chalard setPunctuationSuggestions(); 743549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka } 74417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 74572c5d328882976a0b4ae8b01a872ff5ae4d10547Jean Chalard mConnection.resetCachesUponCursorMove(editorInfo.initialSelStart); 7469d1c73ffd88cd1bfef3de048b0b3a9a7dfbcfa70Jean Chalard 747e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard if (isDifferentTextField) { 74827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 749aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard loadSettings(); 750c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 751aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard if (mSuggest != null && mCurrentSettings.mCorrectionEnabled) { 752aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard mSuggest.setAutoCorrectionThreshold(mCurrentSettings.mAutoCorrectionThreshold); 753aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard } 754aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard 755aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard switcher.loadKeyboard(editorInfo, mCurrentSettings); 7565d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa } else if (restarting) { 7575d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa // TODO: Come up with a more comprehensive way to reset the keyboard layout when 7585d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa // a keyboard layout set doesn't get reloaded in this method. 7595d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa switcher.resetKeyboardStateToAlphabet(); 760d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // In apps like Talk, we come here when the text is sent and the field gets emptied and 761d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // we need to re-evaluate the shift state, but not the whole layout which would be 762d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // disruptive. 763d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka // Space state must be updated before calling updateShiftState 764d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka switcher.updateShiftState(); 765aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard } 766913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShownInternal( 767913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka isSuggestionsStripVisible(), /* needsInputViewShown */ false); 7688e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard 769aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard mLastSelectionStart = editorInfo.initialSelStart; 770aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard mLastSelectionEnd = editorInfo.initialSelEnd; 771aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard 7728e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 7732b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 774c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 7752be2d776649c9c0b3914135794ab7a7e92e753f9Tadashi G. Takaoka mainKeyboardView.setMainDictionaryAvailability(mIsMainDictionaryAvailable); 77627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.setKeyPreviewPopupEnabled(mCurrentSettings.mKeyPreviewPopupOn, 777297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.mKeyPreviewPopupDismissDelay); 7788335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka mainKeyboardView.setGestureHandlingEnabledByUser(mCurrentSettings.mGestureInputEnabled); 7798335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka mainKeyboardView.setGesturePreviewMode(mCurrentSettings.mGesturePreviewTrailEnabled, 7808335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka mCurrentSettings.mGestureFloatingPreviewTextEnabled); 781c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 782c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); 783c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 784c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 785a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback for the TargetApplicationGetter 7867214617622fce8f3fea6620e782c16336260a2a3Jean Chalard @Override 787b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard public void onTargetApplicationKnown(final ApplicationInfo info) { 788b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard mTargetApplicationInfo = info; 789b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard } 790b224b60c94d85f30de93f66685adf06e662618c0Jean Chalard 791923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 792e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka public void onWindowHidden() { 793d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 794d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.latinIME_onWindowHidden(mLastSelectionStart, mLastSelectionEnd, 795d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge getCurrentInputConnection()); 796d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 797e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka super.onWindowHidden(); 798f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 79927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 80027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 80127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 802e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 803e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 80459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputInternal() { 805923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onFinishInput(); 806a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 807979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 80807cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 8090df487678eca58bd4732cfd2b6fd03b3c712eb48Kurt Partridge ResearchLogger.getInstance().latinIME_onFinishInputInternal(); 81007cd1e1731a07ae014a78db59b518ff0dbce3e35Kurt Partridge } 811979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 812f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 81327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 81427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 81527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 816466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 817466741d8a78965b8509bf527344f289e50873092Mike LeBeau 818f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void onFinishInputViewInternal(final boolean finishingInput) { 8196495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa super.onFinishInputView(finishingInput); 820055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardSwitcher.onFinishInputView(); 821f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 82227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 82327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.cancelAllMessages(); 82427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 825d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka // Remove pending messages related to update suggestions 826d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 827edbb65be3e5e391affbf47e134422ac1d1a4ae13Tadashi G. Takaoka resetComposingState(true /* alsoResetLastComposedWord */); 8286495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa } 8296495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa 8306495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa @Override 831f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onUpdateSelection(final int oldSelStart, final int oldSelEnd, 832f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final int newSelStart, final int newSelEnd, 833f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final int composingSpanStart, final int composingSpanEnd) { 834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, 835104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard composingSpanStart, composingSpanEnd); 836466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (DEBUG) { 837466741d8a78965b8509bf527344f289e50873092Mike LeBeau Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart 838466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ose=" + oldSelEnd 839025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lss=" + mLastSelectionStart 840025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lse=" + mLastSelectionEnd 841466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nss=" + newSelStart 842466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nse=" + newSelEnd 843104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", cs=" + composingSpanStart 844104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", ce=" + composingSpanEnd); 845466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 8469bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 847d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge final boolean expectingUpdateSelectionFromLogger = 848d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge ResearchLogger.getAndClearLatinIMEExpectingUpdateSelection(); 8499bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, 8509bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, 851d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge composingSpanEnd, mExpectingUpdateSelection, 85202308bec632a5df23325c916bffec5def16b22b4Jean Chalard expectingUpdateSelectionFromLogger, mConnection); 853d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge if (expectingUpdateSelectionFromLogger) { 854e86054e5c2e4734d87d2fbf1eeba8c75fc888df0Jean Chalard // TODO: Investigate. Quitting now sounds wrong - we won't do the resetting work 855d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge return; 856d67a248de45a698d1009757c9f4e750c77bf35f1Kurt Partridge } 8579bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 858466741d8a78965b8509bf527344f289e50873092Mike LeBeau 859104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // TODO: refactor the following code to be less contrived. 860104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means 861104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // that the cursor is not at the end of the composing span, or there is a selection. 862104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place 863104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // as last time we were called (if there is a selection, it means the start hasn't 864104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // changed, so it's the end that did). 865104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean selectionChanged = (newSelStart != composingSpanEnd 866104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart; 867104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // if composingSpanStart and composingSpanEnd are -1, it means there is no composing 868104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // span in the view - we can use that to narrow down whether the cursor was moved 869104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // by us or not. If we are composing a word but there is no composing span, then 870104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // we know for sure the cursor moved while we were composing and we should reset 871104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // the state. 872104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1; 8735ed88457bf9ef3305d4a5aa4ac05b513433ad0ddJean Chalard if (!mExpectingUpdateSelection 8745ed88457bf9ef3305d4a5aa4ac05b513433ad0ddJean Chalard && !mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart)) { 875cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // TAKE CARE: there is a race condition when we enter this test even when the user 876cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // did not explicitly move the cursor. This happens when typing fast, where two keys 877cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // turn this flag on in succession and both onUpdateSelection() calls arrive after 878cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // the second one - the first call successfully avoids this test, but the second one 879104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // enters. For the moment we rely on noComposingSpan to further reduce the impact. 88051fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 8819a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // TODO: the following is probably better done in resetEntireInputState(). 8829a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // it should only happen when the cursor moved, and the very purpose of the 8839a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // test below is to narrow down whether this happened or not. Likewise with 884fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // the call to updateShiftState. 88551fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // We set this to NONE because after a cursor move, we don't want the space 88651fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // state-related special processing to kick in. 88751fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard mSpaceState = SPACE_STATE_NONE; 88851fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 8898a3d369840d6061692a19ceb1eb7267a50a9e056Jean Chalard if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) { 8906a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // If we are composing a word and moving the cursor, we would want to set a 8916a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // suggestion span for recorrection to work correctly. Unfortunately, that 8926a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // would involve the keyboard committing some new text, which would move the 8936a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // cursor back to where it was. Latin IME could then fix the position of the cursor 8946a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // again, but the asynchronous nature of the calls results in this wreaking havoc 8956a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // with selection on double tap and the like. 8966a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // Another option would be to send suggestions each time we set the composing 8976a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // text, but that is probably too expensive to do, so we decided to leave things 8986a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard // as is. 89928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard resetEntireInputState(newSelStart); 9004c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 901beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 902fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard mKeyboardSwitcher.updateShiftState(); 9034733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 9044733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = false; 9056b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not 9066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // here. It would probably be too expensive to call directly here but we may want to post a 9076b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // message to delay it. The point would be to unify behavior between backspace to the 9086b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // end of a word and manually put the pointer at the end of the word. 909466741d8a78965b8509bf527344f289e50873092Mike LeBeau 910979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Make a note of the cursor position 911979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionStart = newSelStart; 912979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionEnd = newSelEnd; 9131931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mSubtypeState.currentSubtypeUsed(); 9147a8dac55278cedd838be325f56b4c52d973c61f5satok } 9157a8dac55278cedd838be325f56b4c52d973c61f5satok 916c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 917c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has clicked on the extracted text view, 918c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * when running in fullscreen mode. The default implementation hides 919913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * the suggestions view when this happens, but only if the extracted text 920c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * editor has a vertical scroll bar because its text doesn't fit. 921c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 922913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 923c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 924c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 925c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedTextClicked() { 926fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; 927c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 928c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedTextClicked(); 929c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 930c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 931c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 932c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has performed a cursor movement in the 933c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * extracted text view, when it is running in fullscreen mode. The default 934913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * implementation hides the suggestions view when a vertical movement 935c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * happens, but only if the extracted text editor has a vertical scroll bar 936c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * because its text doesn't fit. 937c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 938913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 939c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 940c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 941f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onExtractedCursorMovement(final int dx, final int dy) { 942fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) return; 943c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 944c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedCursorMovement(dx, dy); 945c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 946c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void hideWindow() { 949979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 950c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mKeyboardSwitcher.onHideWindow(); 951979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (TRACE) Debug.stopMethodTracing(); 9536e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani if (mOptionsDialog != null && mOptionsDialog.isShowing()) { 9546e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog.dismiss(); 9556e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog = null; 9566e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.hideWindow(); 958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 961f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onDisplayCompletions(final CompletionInfo[] applicationSpecifiedCompletions) { 962979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG) { 963a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa Log.i(TAG, "Received completions:"); 964bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok if (applicationSpecifiedCompletions != null) { 965bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 966bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); 967bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok } 968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 970dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (!mCurrentSettings.isApplicationSpecifiedCompletionsOn()) return; 971dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; 972dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (applicationSpecifiedCompletions == null) { 973259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 97494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 97594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(null); 97694e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 977dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard return; 978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 979dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard 980dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = 981dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard SuggestedWords.getFromApplicationSpecifiedCompletions( 982dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard applicationSpecifiedCompletions); 983dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final SuggestedWords suggestedWords = new SuggestedWords( 984dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard applicationSuggestedWords, 985dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* typedWordValid */, 986dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* hasAutoCorrectionCandidate */, 987dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isPunctuationSuggestions */, 988dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isObsoleteSuggestions */, 989dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard false /* isPrediction */); 990dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // When in fullscreen mode, show completions generated by the application 991dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard final boolean isAutoCorrection = false; 992259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(suggestedWords, isAutoCorrection); 993dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard setAutoCorrectionIndicator(isAutoCorrection); 994dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // TODO: is this the right thing to do? What should we auto-correct to in 995dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard // this case? This says to keep whatever the user typed. 996dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 997dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard setSuggestionStripShown(true); 99894e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 99994e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); 100094e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 1001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1003f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void setSuggestionStripShownInternal(final boolean shown, 1004f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final boolean needsInputViewShown) { 1005913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // TODO: Modify this if we support suggestions with hard keyboard 1006913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { 100727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 100827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final boolean inputViewShown = (mainKeyboardView != null) 100927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka ? mainKeyboardView.isShown() : false; 1010913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean shouldShowSuggestions = shown 1011433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka && (needsInputViewShown ? inputViewShown : true); 10124b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka if (isFullscreenMode()) { 1013913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 1014913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.GONE); 10157a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } else { 1016913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 1017913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); 10187a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } 1019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1021a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1022f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void setSuggestionStripShown(final boolean shown) { 1023c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); 1024543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa } 1025543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa 1026bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka private int getAdjustedBackingViewHeight() { 1027bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka final int currentHeight = mKeyPreviewBackingView.getHeight(); 1028bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka if (currentHeight > 0) { 1029bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return currentHeight; 1030c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 1031c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 1032f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 103327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView == null) { 1034bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return 0; 1035bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka } 103627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final int keyboardHeight = mainKeyboardView.getHeight(); 1037c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int suggestionsHeight = mSuggestionsContainer.getHeight(); 1038c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int displayHeight = mResources.getDisplayMetrics().heightPixels; 1039c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final Rect rect = new Rect(); 1040c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); 1041c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int notificationBarHeight = rect.top; 1042c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight 1043c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka - keyboardHeight; 1044c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 1045c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final LayoutParams params = mKeyPreviewBackingView.getLayoutParams(); 10464702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka params.height = mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight); 1047c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.setLayoutParams(params); 1048bc5b89cdff7065b7eab0b9f230b37084d9a6446fTadashi G. Takaoka return params.height; 1049c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 1050c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 1051543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa @Override 1052f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onComputeInsets(final InputMethodService.Insets outInsets) { 1053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onComputeInsets(outInsets); 1054f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 105527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView == null || mSuggestionsContainer == null) { 105646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka return; 105727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 1058b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int adjustedBackingHeight = getAdjustedBackingViewHeight(); 1059b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); 1060b94f4cc71c5cbf84d07166efa42991ba96d93c73Tadashi G. Takaoka final int backingHeight = backingGone ? 0 : adjustedBackingHeight; 1061d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // In fullscreen mode, the height of the extract area managed by InputMethodService should 1062d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // be considered. 1063d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. 1064d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0; 106559010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0 106659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka : mSuggestionsContainer.getHeight(); 1067d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extraHeight = extractHeight + backingHeight + suggestionsHeight; 1068fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang int visibleTopY = extraHeight; 10699e347d3d448e48229c46aad394ec9bd60cd5807bsatok // Need to set touchable region only if input view is being shown 107027e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView.isShown()) { 1071913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { 1072fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang visibleTopY -= suggestionsHeight; 10739e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 1074fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang final int touchY = mainKeyboardView.isShowingMoreKeysPanel() ? 0 : visibleTopY; 107527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final int touchWidth = mainKeyboardView.getWidth(); 107627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final int touchHeight = mainKeyboardView.getHeight() + extraHeight 10777a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka // Extend touchable region below the keyboard. 10787a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + EXTENDED_TOUCHABLE_REGION_HEIGHT; 107913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; 108013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight); 10819e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 1082fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang outInsets.contentTopInsets = visibleTopY; 1083fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang outInsets.visibleTopInsets = visibleTopY; 1084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1085a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1086923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 1087979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean onEvaluateFullscreenMode() { 10889751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka // Reread resource value here, because this method is called by framework anytime as needed. 10899751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka final boolean isFullscreenModeAllowed = 10902da886651874b2588f18f800417ba858ac93d88bJean Chalard SettingsValues.isFullscreenModeAllowed(getResources()); 109160dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { 109260dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI 109360dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // implies NO_FULLSCREEN. However, the framework mistakenly does. i.e. NO_EXTRACT_UI 109460dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // without NO_FULLSCREEN doesn't work as expected. Because of this we need this 109560dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka // hack for now. Let's get rid of this once the framework gets fixed. 109660dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka final EditorInfo ei = getCurrentInputEditorInfo(); 109760dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka return !(ei != null && ((ei.imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0)); 109860dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka } else { 109960dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka return false; 110060dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka } 110159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka } 110259010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka 110359010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka @Override 110459010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka public void updateFullscreenMode() { 110559010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka super.updateFullscreenMode(); 1106f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka 110759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka if (mKeyPreviewBackingView == null) return; 1108549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka // In fullscreen mode, no need to have extra space to show the key preview. 110959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka // If not, we should have extra space above the keyboard to show the key preview. 1110549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); 1111979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1112979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 11132649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // This will reset the whole input state to the starting state. It will clear 11144a5cb5c36a6a385ec0036981a0e93b0253e884b0Jean Chalard // the composing word, reset the last composed word, tell the inputconnection about it. 111528d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard private void resetEntireInputState(final int newCursorPosition) { 11162649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 1117ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard if (mCurrentSettings.mBigramPredictionEnabled) { 1118ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard clearSuggestionStrip(); 1119ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard } else { 1120ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); 1121ac25fcac717b0d28dfb2cd5c8ecd4fde839c4eebJean Chalard } 112228d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard mConnection.resetCachesUponCursorMove(newCursorPosition); 11232649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard } 11242649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard 11252692a8700737d8eed268039aa27b22a31669da08Jean Chalard private void resetComposingState(final boolean alsoResetLastComposedWord) { 11262692a8700737d8eed268039aa27b22a31669da08Jean Chalard mWordComposer.reset(); 11272692a8700737d8eed268039aa27b22a31669da08Jean Chalard if (alsoResetLastComposedWord) 11282692a8700737d8eed268039aa27b22a31669da08Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 11292692a8700737d8eed268039aa27b22a31669da08Jean Chalard } 11302692a8700737d8eed268039aa27b22a31669da08Jean Chalard 1131a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard private void commitTyped(final String separatorString) { 1132196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) return; 1133bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 11343651220327c051d8017045aa5e8919461507b3f8Jean Chalard if (typedWord.length() > 0) { 11356a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard commitChosenWord(typedWord, LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, 11366a58bb7ac95e804f87c4e88b5eb970d28210518eJean Chalard separatorString); 1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1140a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from the KeyboardSwitcher which needs to know auto caps state to display 1141a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // the right layout. 1142553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka public int getCurrentAutoCapsState() { 1143297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mCurrentSettings.mAutoCap) return Constants.TextUtils.CAP_MODE_OFF; 114403ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka 114503ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final EditorInfo ei = getCurrentInputEditorInfo(); 1146553e2f19c1607080ff874cb642237f947809cdb3Tadashi G. Takaoka if (ei == null) return Constants.TextUtils.CAP_MODE_OFF; 114703ca17c8415854c4c949b92b66543c920562ac3dTadashi G. Takaoka final int inputType = ei.inputType; 114890a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Warning: this depends on mSpaceState, which may not be the most current value. If 114990a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // mSpaceState gets updated later, whoever called this may need to be told about it. 115090a91272447fd64bc54e06f08f45b11c45930767Jean Chalard return mConnection.getCursorCapsMode(inputType, mSubtypeSwitcher.getCurrentSubtypeLocale(), 115190a91272447fd64bc54e06f08f45b11c45930767Jean Chalard SPACE_STATE_PHANTOM == mSpaceState); 11521c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 11531c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1154adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard // Factor in auto-caps and manual caps and compute the current caps mode. 1155adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard private int getActualCapsMode() { 11566686e63f2158eff07e39ff002ba211d0578f2a4fJean Chalard final int keyboardShiftMode = mKeyboardSwitcher.getKeyboardShiftMode(); 11576686e63f2158eff07e39ff002ba211d0578f2a4fJean Chalard if (keyboardShiftMode != WordComposer.CAPS_MODE_AUTO_SHIFTED) return keyboardShiftMode; 1158adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard final int auto = getCurrentAutoCapsState(); 1159adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard if (0 != (auto & TextUtils.CAP_MODE_CHARACTERS)) { 1160adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return WordComposer.CAPS_MODE_AUTO_SHIFT_LOCKED; 1161adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard } 1162adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard if (0 != auto) return WordComposer.CAPS_MODE_AUTO_SHIFTED; 1163adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard return WordComposer.CAPS_MODE_OFF; 1164adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard } 1165adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard 1166bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard private void swapSwapperAndSpace() { 11675475b38328171a0841ae18074bd45380ec567e90Jean Chalard CharSequence lastTwo = mConnection.getTextBeforeCursor(2, 0); 1168863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. 1169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastTwo != null && lastTwo.length() == 2 1170240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastTwo.charAt(0) == Constants.CODE_SPACE) { 11715475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 11725475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(lastTwo.charAt(1) + " ", 1); 1173d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 117494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_swapSwapperAndSpace(); 1175d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge } 1176b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 11774ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 11784ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 11794ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 11802b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private boolean maybeDoubleSpacePeriod() { 11812f3a694e29ad5a63052a2f963327855fee099f55Jean Chalard if (!mCurrentSettings.mCorrectionEnabled) return false; 1182139bd83f0c552e3fdb5f763b5f6fe25ad138802bKen Wakasa if (!mCurrentSettings.mUseDoubleSpacePeriod) return false; 11832b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa if (!mHandler.isAcceptingDoubleSpacePeriod()) return false; 11845475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastThree = mConnection.getTextBeforeCursor(3, 0); 1185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastThree != null && lastThree.length() == 3 11862b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa && canBeFollowedByDoubleSpacePeriod(lastThree.charAt(0)) 1187240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastThree.charAt(1) == Constants.CODE_SPACE 1188240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastThree.charAt(2) == Constants.CODE_SPACE) { 11892b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 11905475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(2, 0); 11915475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(". ", 1); 1192b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1193120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 1194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1195120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return false; 1196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1197a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 11982b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa private static boolean canBeFollowedByDoubleSpacePeriod(final int codePoint) { 1199344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: Check again whether there really ain't a better way to check this. 1200344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka // TODO: This should probably be language-dependant... 1201344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka return Character.isLetterOrDigit(codePoint) 1202240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_SINGLE_QUOTE 1203240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_DOUBLE_QUOTE 1204240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_PARENTHESIS 1205240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_SQUARE_BRACKET 1206240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_CURLY_BRACKET 1207240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka || codePoint == Constants.CODE_CLOSING_ANGLE_BRACKET; 1208344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka } 1209344af156744c6866090fb70f151efd66668c1e20Tadashi G. Takaoka 12104702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is 12114702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // pressed. 1212c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 1213f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean addWordToUserDictionary(final String word) { 121467fd0c240d7c37b06e05333347fd17acf59fadf8Jean Chalard mUserDictionary.addWordToUserDictionary(word, 128); 1215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1218f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static boolean isAlphabet(final int code) { 12198fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka return Character.isLetter(code); 1220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1221a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1222e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka private void onSettingsKeyPressed() { 1223cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return; 1224911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa showSubtypeSelectorAndSettings(); 12259a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 12269a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1227cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa // Virtual codes representing custom requests. These are used in onCustomRequest() below. 1228cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; 1229cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa 1230cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa @Override 1231f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean onCustomRequest(final int requestCode) { 1232cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return false; 1233cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa switch (requestCode) { 1234cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa case CODE_SHOW_INPUT_METHOD_PICKER: 12356fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { 12366fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mRichImm.getInputMethodManager().showInputMethodPicker(); 1237cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return true; 12389a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1239cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 12409a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1241cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 12429a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 12439a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 12449a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok private boolean isShowingOptionDialog() { 12459a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok return mOptionsDialog != null && mOptionsDialog.isShowing(); 12469a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 12479a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1248f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static int getActionId(final Keyboard keyboard) { 124905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE; 12507a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12517a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 1252f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void performEditorAction(final int actionId) { 12535475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.performEditorAction(actionId); 12547a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12557a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 1256aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka // TODO: Revise the language switch key behavior to make it much smarter and more reasonable. 125781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private void handleLanguageSwitchKey() { 125881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final IBinder token = getWindow().getWindow().getAttributes().token; 1259aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka if (mCurrentSettings.mIncludesOtherImesInLanguageSwitchList) { 12606fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */); 1261aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka return; 1262aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka } 12631931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mSubtypeState.switchSubtype(token, mRichImm); 126481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 126581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka 126628d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard private void sendDownUpKeyEventForBackwardCompatibility(final int code) { 12674e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard final long eventTime = SystemClock.uptimeMillis(); 12685475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(eventTime, eventTime, 12694e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_DOWN, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 12704e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 12715475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, 12724e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.ACTION_UP, code, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 12734e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE)); 12744e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 12754e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard 1276f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void sendKeyCodePoint(final int code) { 12777a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // TODO: Remove this special handling of digit letters. 12787a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. 12797a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (code >= '0' && code <= '9') { 128028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard sendDownUpKeyEventForBackwardCompatibility(code - '0' + KeyEvent.KEYCODE_0); 128194e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 128294e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_sendKeyCodePoint(code); 128394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 12847a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return; 12857a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12867a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 12875475b38328171a0841ae18074bd45380ec567e90Jean Chalard // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because 12885475b38328171a0841ae18074bd45380ec567e90Jean Chalard // we want to be able to compile against the Ice Cream Sandwich SDK. 1289240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_ENTER == code && mTargetApplicationInfo != null 12905475b38328171a0841ae18074bd45380ec567e90Jean Chalard && mTargetApplicationInfo.targetSdkVersion < 16) { 12915475b38328171a0841ae18074bd45380ec567e90Jean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 12925475b38328171a0841ae18074bd45380ec567e90Jean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 12935475b38328171a0841ae18074bd45380ec567e90Jean Chalard // reasons (there are race conditions with commits) but some applications are 12945475b38328171a0841ae18074bd45380ec567e90Jean Chalard // relying on this behavior so we continue to support it for older apps. 129528d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard sendDownUpKeyEventForBackwardCompatibility(KeyEvent.KEYCODE_ENTER); 12965475b38328171a0841ae18074bd45380ec567e90Jean Chalard } else { 12975475b38328171a0841ae18074bd45380ec567e90Jean Chalard final String text = new String(new int[] { code }, 0, 1); 12985475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, text.length()); 12995475b38328171a0841ae18074bd45380ec567e90Jean Chalard } 13007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 13017a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 13025f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Implementation of {@link KeyboardActionListener}. 13035a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1304f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onCodeInput(final int primaryCode, final int x, final int y) { 1305175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final long when = SystemClock.uptimeMillis(); 1306240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (primaryCode != Constants.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { 1307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDeleteCount = 0; 1308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mLastKeyTime = when; 1310f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 1311175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1312120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // The space state depends only on the last character pressed and its own previous 1313120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // state. Here, we revert the space state to neutral if the key is actually modifying 1314120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // the input contents (any non-shift key), which is what we should do for 1315120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // all inputs that do not result in a special state. Each character handling is then 1316120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // free to override the state as they see fit. 1317120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState = mSpaceState; 131870852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false; 1319ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 13202b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa // TODO: Consolidate the double-space period timer, mLastKeyTime, and the space state. 1321240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (primaryCode != Constants.CODE_SPACE) { 13222b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 1323ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa } 1324ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1325c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 1327240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_DELETE: 1328120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1329120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleBackspace(spaceState); 13304189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka mDeleteCount++; 13314733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 1332140467b8b65eb9087a9b7f744dbb8a30481effe7Kurt Partridge LatinImeLogger.logOnDelete(x, y); 13334189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1334240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 1335240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SWITCH_ALPHA_SYMBOL: 13362a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka // Shift and symbol key is handled in onPressKey() and onReleaseKey(). 13374189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1338240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SETTINGS: 133993246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka onSettingsKeyPressed(); 13404189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1341240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHORTCUT: 13429fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka mSubtypeSwitcher.switchToShortcutIME(this); 13434189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1344240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_ACTION_ENTER: 13458f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(getActionId(switcher.getKeyboard())); 13467a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka break; 1347240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_ACTION_NEXT: 13488f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_NEXT); 134905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka break; 1350240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_ACTION_PREVIOUS: 13518f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); 13524189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1353240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_LANGUAGE_SWITCH: 135481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka handleLanguageSwitchKey(); 135581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka break; 1356240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_RESEARCH: 1357724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 135858eb4d9f27595202927150766d198a0bff15efadKurt Partridge ResearchLogger.getInstance().onResearchKeySelected(this); 1359724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge } 1360724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge break; 13614189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka default: 1362120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1363297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWordSeparator(primaryCode)) { 1364c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); 13654189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 13664be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (SPACE_STATE_PHANTOM == spaceState) { 136787cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 136887cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) { 136987cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onAutoCorrection( 137087cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka "", mWordComposer.getTypedWord(), " ", mWordComposer); 137187cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 137287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 13734be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka commitTyped(LastComposedWord.NOT_A_SEPARATOR); 13744be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 1375eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final int keyX, keyY; 13768dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 13778dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { 1378eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang keyX = x; 1379eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang keyY = y; 13808dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } else { 1381ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka keyX = Constants.NOT_A_COORDINATE; 1382ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka keyY = Constants.NOT_A_COORDINATE; 13838dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } 1384eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang handleCharacter(primaryCode, keyX, keyY, spaceState); 13854189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 13864733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 13874733609947c0ec74e460bd714fffca0518ade93aJean Chalard break; 1388923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1389eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka switcher.onCodeInput(primaryCode); 1390125de3dfdf548359de890247907f2e6f430008ecJean Chalard // Reset after any single keystroke, except shift and symbol-shift 1391240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (!didAutoCorrect && primaryCode != Constants.CODE_SHIFT 1392240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && primaryCode != Constants.CODE_SWITCH_ALPHA_SYMBOL) 1393c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard mLastComposedWord.deactivate(); 1394240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_DELETE != primaryCode) { 1395a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mEnteredText = null; 1396a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard } 1397e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard mConnection.endBatchEdit(); 1398bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 1399bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge ResearchLogger.latinIME_onCodeInput(primaryCode, x, y); 1400bf653996eab40e2c66cfd2eaeb48ed5175b78455Kurt Partridge } 1401923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1402a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1403a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from PointerTracker through the KeyboardActionListener interface 14045a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1405bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void onTextInput(final String rawText) { 1406f254e3fec7744dc1eb2cc09ac157986c3b2b5408Jean Chalard mConnection.beginBatchEdit(); 14076c70b9200340537d05ff8932d7cd990269eb486dJean Chalard if (mWordComposer.isComposingWord()) { 1408a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard commitCurrentAutoCorrection(rawText.toString()); 1409a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard } else { 1410a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 14116c70b9200340537d05ff8932d7cd990269eb486dJean Chalard } 14120a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka mHandler.postUpdateSuggestionStrip(); 1413bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String text = specificTldProcessingOnTextInput(rawText); 1414fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == mSpaceState) { 14150e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 1416fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 14175475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitText(text, 1); 14185475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.endBatchEdit(); 141990a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Space state must be updated before calling updateShiftState 142090a91272447fd64bc54e06f08f45b11c45930767Jean Chalard mSpaceState = SPACE_STATE_NONE; 1421b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1422240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka mKeyboardSwitcher.onCodeInput(Constants.CODE_OUTPUT_TEXT); 1423dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = text; 1424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 14264be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 14274be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka public void onStartBatchInput() { 142858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka BatchInputUpdater.getInstance().onStartBatchInput(); 14294be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.beginBatchEdit(); 14304be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (mWordComposer.isComposingWord()) { 143187cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 143287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (mWordComposer.isBatchMode()) { 143387cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer); 143487cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 143587cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 1436b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard if (mWordComposer.size() <= 1) { 1437b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // We auto-correct the previous (typed, not gestured) string iff it's one character 1438b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // long. The reason for this is, even in the middle of gesture typing, you'll still 1439b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // tap one-letter words and you want them auto-corrected (typically, "i" in English 1440b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // should become "I"). However for any longer word, we assume that the reason for 1441b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // tapping probably is that the word you intend to type is not in the dictionary, 1442b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // so we do not attempt to correct, on the assumption that if that was a dictionary 1443b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard // word, the user would probably have gestured instead. 1444b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard commitCurrentAutoCorrection(LastComposedWord.NOT_A_SEPARATOR); 1445b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard } else { 1446b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 1447b4e74cfc87ccb0523da18cb9fe30a6d08d1a04e2Jean Chalard } 14484be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mExpectingUpdateSelection = true; 1449e4783f95b2ad9f46ece34103cbe4d8eb5ea8afcaJean Chalard // The following is necessary for the case where the user typed something but didn't 1450e4783f95b2ad9f46ece34103cbe4d8eb5ea8afcaJean Chalard // manual pick it and didn't input any separator. 14514be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mSpaceState = SPACE_STATE_PHANTOM; 1452e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard } else { 1453e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); 1454f960eb186d63aa4f9fecd22f036fc8724d39d949Jean Chalard // TODO: reverse this logic. We should have the means to determine whether a character 1455f960eb186d63aa4f9fecd22f036fc8724d39d949Jean Chalard // should usually be followed by a space, and it should be more readable. 1456e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard if (Constants.NOT_A_CODE != codePointBeforeCursor 1457f960eb186d63aa4f9fecd22f036fc8724d39d949Jean Chalard && !Character.isWhitespace(codePointBeforeCursor) 1458f960eb186d63aa4f9fecd22f036fc8724d39d949Jean Chalard && !mCurrentSettings.isPhantomSpacePromotingSymbol(codePointBeforeCursor) 1459f960eb186d63aa4f9fecd22f036fc8724d39d949Jean Chalard && !mCurrentSettings.isWeakSpaceStripper(codePointBeforeCursor)) { 1460e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1461e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard } 14624be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 14634be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.endBatchEdit(); 1464adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); 1465eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang } 1466eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang 1467f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final class BatchInputUpdater implements Handler.Callback { 1468f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private final Handler mHandler; 1469f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private LatinIME mLatinIme; 1470b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka private boolean mInBatchInput; // synchronized using "this". 1471f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1472f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private BatchInputUpdater() { 1473f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final HandlerThread handlerThread = new HandlerThread( 1474f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka BatchInputUpdater.class.getSimpleName()); 1475f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka handlerThread.start(); 1476f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mHandler = new Handler(handlerThread.getLooper(), this); 1477f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1478f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1479f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka // Initialization-on-demand holder 1480f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final class OnDemandInitializationHolder { 1481f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public static final BatchInputUpdater sInstance = new BatchInputUpdater(); 1482f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1483f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1484f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public static BatchInputUpdater getInstance() { 1485f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return OnDemandInitializationHolder.sInstance; 1486f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1487f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1488f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private static final int MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 1; 1489f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1490f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka @Override 1491f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean handleMessage(final Message msg) { 1492f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka switch (msg.what) { 1493f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka case MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP: 149458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka updateBatchInput((InputPointers)msg.obj, mLatinIme); 1495f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka break; 1496f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1497f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return true; 1498f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1499f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 150058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the UI thread. 150158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka public synchronized void onStartBatchInput() { 1502b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka mHandler.removeMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP); 150358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mInBatchInput = true; 150458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 150558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 150658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the Handler thread. 150758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private synchronized void updateBatchInput(final InputPointers batchPointers, 1508f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final LatinIME latinIme) { 150958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka if (!mInBatchInput) { 1510b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka // Batch input has ended or canceled while the message was being delivered. 151158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return; 151258fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 151358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked( 151458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka batchPointers, latinIme); 151558fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka latinIme.mHandler.showGesturePreviewAndSuggestionStrip( 151658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka suggestedWords, false /* dismissGestureFloatingPreviewText */); 151758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka } 151858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka 151958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the UI thread. 152058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka public void onUpdateBatchInput(final InputPointers batchPointers, final LatinIME latinIme) { 1521f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mLatinIme = latinIme; 1522f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka if (mHandler.hasMessages(MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP)) { 1523f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return; 1524f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1525f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mHandler.obtainMessage( 1526f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka MSG_UPDATE_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, batchPointers) 1527f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka .sendToTarget(); 1528f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1529f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1530b5fc0e02d04550d39bfa98c2dde805f1c1d3f9a3Tadashi G. Takaoka public synchronized void onCancelBatchInput(final LatinIME latinIme) { 1531b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka mInBatchInput = false; 1532b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka latinIme.mHandler.showGesturePreviewAndSuggestionStrip( 1533b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka SuggestedWords.EMPTY, true /* dismissGestureFloatingPreviewText */); 1534b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1535b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 153658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka // Run in the UI thread. 153758fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka public synchronized SuggestedWords onEndBatchInput(final InputPointers batchPointers, 153858fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final LatinIME latinIme) { 153958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka mInBatchInput = false; 154058fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWordsGestureLocked( 154158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka batchPointers, latinIme); 1542f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka latinIme.mHandler.showGesturePreviewAndSuggestionStrip( 154358fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka suggestedWords, true /* dismissGestureFloatingPreviewText */); 154458fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka return suggestedWords; 1545f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1546f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1547f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka // {@link LatinIME#getSuggestedWords(int)} method calls with same session id have to 1548f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka // be synchronized. 154958fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka private static SuggestedWords getSuggestedWordsGestureLocked( 1550f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final InputPointers batchPointers, final LatinIME latinIme) { 1551f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka latinIme.mWordComposer.setBatchInputPointers(batchPointers); 1552f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka return latinIme.getSuggestedWords(Suggest.SESSION_GESTURE); 1553f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1554f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1555f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1556f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords, 1557f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final boolean dismissGestureFloatingPreviewText) { 1558f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka showSuggestionStrip(suggestedWords, null); 15598e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka final KeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 1560f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka if (dismissGestureFloatingPreviewText) { 1561f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mainKeyboardView.dismissGestureFloatingPreviewText(); 15628e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka } else { 15638e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka final String batchInputText = suggestedWords.isEmpty() 15648e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka ? null : suggestedWords.getWord(0); 15658e2b34cdb24adb1563cc296a4741be7391fa24e9Tadashi G. Takaoka mainKeyboardView.showGestureFloatingPreviewText(batchInputText); 1566f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 15674be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 15684be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 15694be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka @Override 1570f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onUpdateBatchInput(final InputPointers batchPointers) { 157158fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka BatchInputUpdater.getInstance().onUpdateBatchInput(batchPointers, this); 1572f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka } 1573f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka 1574f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka @Override 1575f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onEndBatchInput(final InputPointers batchPointers) { 157658fe5a421f3334641209300c5bc60c0e6a842220Tadashi G. Takaoka final SuggestedWords suggestedWords = BatchInputUpdater.getInstance().onEndBatchInput( 1577f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka batchPointers, this); 1578c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka final String batchInputText = suggestedWords.isEmpty() 1579c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka ? null : suggestedWords.getWord(0); 1580f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka if (TextUtils.isEmpty(batchInputText)) { 158110102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka return; 158210102f02af1216cfca115d1742740f567b909e2cTadashi G. Takaoka } 1583f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mWordComposer.setBatchInputWord(batchInputText); 15844be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.beginBatchEdit(); 15854be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka if (SPACE_STATE_PHANTOM == mSpaceState) { 15860e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 15874be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 1588f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka mConnection.setComposingText(batchInputText, 1); 15894be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mExpectingUpdateSelection = true; 15904be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mConnection.endBatchEdit(); 159190a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Space state must be updated before calling updateShiftState 15924be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mSpaceState = SPACE_STATE_PHANTOM; 159390a91272447fd64bc54e06f08f45b11c45930767Jean Chalard mKeyboardSwitcher.updateShiftState(); 15944be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 15954be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka 1596bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String specificTldProcessingOnTextInput(final String text) { 1597240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (text.length() <= 1 || text.charAt(0) != Constants.CODE_PERIOD 1598fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard || !Character.isLetter(text.charAt(1))) { 1599fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Not a tld: do nothing. 1600fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1601fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 160212d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // We have a TLD (or something that looks like this): make sure we don't add 160312d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // a space even if currently in phantom mode. 160412d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard mSpaceState = SPACE_STATE_NONE; 1605e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard // TODO: use getCodePointBeforeCursor instead to improve performance and simplify the code 16065475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastOne = mConnection.getTextBeforeCursor(1, 0); 1607fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (lastOne != null && lastOne.length() == 1 1608240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka && lastOne.charAt(0) == Constants.CODE_PERIOD) { 1609bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka return text.substring(1); 1610fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else { 1611fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1612fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1613fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1614fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1615a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from PointerTracker through the KeyboardActionListener interface 16165a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 16178aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() { 161883e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka // User released a finger outside any key 16195f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka mKeyboardSwitcher.onCancelInput(); 162083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } 162183e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka 1622b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka @Override 1623b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka public void onCancelBatchInput() { 1624b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka BatchInputUpdater.getInstance().onCancelBatchInput(this); 1625b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka } 1626b3f789799a2983a9c97288686f11dfab369243c0Tadashi G. Takaoka 1627120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleBackspace(final int spaceState) { 1628fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // In many cases, we may have to put the keyboard in auto-shift state again. However 1629fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // we want to wait a few milliseconds before doing it to avoid the keyboard flashing 1630fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard // during key repeat. 1631beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 16322245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard 1633196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 16343651220327c051d8017045aa5e8919461507b3f8Jean Chalard final int length = mWordComposer.size(); 1635923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (length > 0) { 163601d47b809617aee03e240a6b4b41013269547bc1Jean Chalard if (mWordComposer.isBatchMode()) { 16374be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mWordComposer.reset(); 16384be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } else { 16394be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka mWordComposer.deleteLast(); 16404be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka } 16415475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1642a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 1643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 16445475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1646890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } else { 16475935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard if (mLastComposedWord.canRevertCommit()) { 164887cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 164987cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onAutoCorrectionCancellation(); 165087cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 16515475b38328171a0841ae18074bd45380ec567e90Jean Chalard revertCommit(); 1652120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return; 1653120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1654a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) { 1655a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // Cancel multi-character input: remove the text we just entered. 1656a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // This is triggered on backspace after a key that inputs multiple characters, 1657a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // like the smiley key or the .com key. 1658a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard final int length = mEnteredText.length(); 1659a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mConnection.deleteSurroundingText(length, 0); 1660a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mEnteredText = null; 1661a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. 1662a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // In addition we know that spaceState is false, and that we should not be 1663a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // reverting any autocorrect at this point. So we can safely return. 1664a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard return; 1665a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard } 1666d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (SPACE_STATE_DOUBLE == spaceState) { 16672b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.cancelDoubleSpacePeriodTimer(); 1668a32eb2721390d5964c83c787ad30fd3f61b936b0Jean Chalard if (mConnection.revertDoubleSpace()) { 1669d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // No need to reset mSpaceState, it has already be done (that's why we 1670d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // receive it as a parameter) 1671d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1672d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 1673d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 16742010aad741bc1a7266913bcb8b8348d6e401c95bJean Chalard if (mConnection.revertSwapPunctuation()) { 1675d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // Likewise 1676d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1677d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 16784733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 1679504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka 16804fef31510df542a3324426a6750950194d016086Jean Chalard // No cancelling of commit/double space/swap: we have a regular backspace. 16814fef31510df542a3324426a6750950194d016086Jean Chalard // We should backspace one char and restart suggestion if at the end of a word. 16824fef31510df542a3324426a6750950194d016086Jean Chalard if (mLastSelectionStart != mLastSelectionEnd) { 16834fef31510df542a3324426a6750950194d016086Jean Chalard // If there is a selection, remove it. 16844fef31510df542a3324426a6750950194d016086Jean Chalard final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; 16855475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); 16865475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(lengthToDelete, 0); 16876558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } else { 16884fef31510df542a3324426a6750950194d016086Jean Chalard // There is no selection, just delete one character. 16894fef31510df542a3324426a6750950194d016086Jean Chalard if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { 16904fef31510df542a3324426a6750950194d016086Jean Chalard // This should never happen. 16914fef31510df542a3324426a6750950194d016086Jean Chalard Log.e(TAG, "Backspace when we don't know the selection position"); 16926558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 16934e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // 16 is android.os.Build.VERSION_CODES.JELLY_BEAN but we can't write it because 16944e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // we want to be able to compile against the Ice Cream Sandwich SDK. 16954e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard if (mTargetApplicationInfo != null 16964e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard && mTargetApplicationInfo.targetSdkVersion < 16) { 16974e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 16984e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // a hardware keyboard event on pressing enter or delete. This is bad for many 16994e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // reasons (there are race conditions with commits) but some applications are 17004e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard // relying on this behavior so we continue to support it for older apps. 170128d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard sendDownUpKeyEventForBackwardCompatibility(KeyEvent.KEYCODE_DEL); 17024e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } else { 17035475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 17044e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalard } 17054fef31510df542a3324426a6750950194d016086Jean Chalard if (mDeleteCount > DELETE_ACCELERATE_AT) { 17065475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 1707edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1709fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { 17105475b38328171a0841ae18074bd45380ec567e90Jean Chalard restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(); 17114fef31510df542a3324426a6750950194d016086Jean Chalard } 1712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1713923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1714923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1715e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard private boolean maybeStripSpace(final int code, 1716e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final int spaceState, final boolean isFromSuggestionStrip) { 1717240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1718bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1719e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1720e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else if ((SPACE_STATE_WEAK == spaceState 1721e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard || SPACE_STATE_SWAP_PUNCTUATION == spaceState) 1722e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard && isFromSuggestionStrip) { 1723297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWeakSpaceSwapper(code)) { 1724e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return true; 1725e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1726297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (mCurrentSettings.isWeakSpaceStripper(code)) { 1727bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard mConnection.removeTrailingSpace(); 1728e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1729e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1730e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1731e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1732e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1733e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1734e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1735e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1736ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void handleCharacter(final int primaryCode, final int x, 1737120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int y, final int spaceState) { 1738196d82cdd740580ed79d801483dbc282be85d076Jean Chalard boolean isComposingWord = mWordComposer.isComposingWord(); 1739fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1740fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1741297e6d590bd957577c335aa8713a786145a70288Jean Chalard !mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) { 1742fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (isComposingWord) { 1743fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Sanity check 1744fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard throw new RuntimeException("Should not be composing here"); 1745fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 17460e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 1747fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1748fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1749d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // NOTE: isCursorTouchingWord() is a blocking IPC call, so it often takes several 1750d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // dozen milliseconds. Avoid calling it as much as possible, since we are on the UI 1751d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard // thread here. 1752d5cd7e64aa30096241f63e47a9169699bdd98231Jean Chalard if (!isComposingWord && (isAlphabet(primaryCode) 1753297e6d590bd957577c335aa8713a786145a70288Jean Chalard || mCurrentSettings.isSymbolExcludedFromWordSeparators(primaryCode)) 1754fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard && mCurrentSettings.isSuggestionsRequested(mDisplayOrientation) && 1755297e6d590bd957577c335aa8713a786145a70288Jean Chalard !mConnection.isCursorTouchingWord(mCurrentSettings)) { 1756736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Reset entirely the composing state anyway, then start composing a new word unless 1757736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // the character is a single quote. The idea here is, single quote is not a 1758736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // separator and it should be treated as a normal character, except in the first 1759736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // position where it should not start composing a word. 1760240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka isComposingWord = (Constants.CODE_SINGLE_QUOTE != primaryCode); 1761736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // Here we don't need to reset the last composed word. It will be reset 1762736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // when we commit this one, if we ever do; if on the other hand we backspace 1763736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // it entirely and resume suggestions on the previous word, we'd like to still 1764736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard // have touch coordinates for it. 1765736b109e1692374f5a2739885c8f931dbb8be1f2Jean Chalard resetComposingState(false /* alsoResetLastComposedWord */); 1766923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 17677b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (isComposingWord) { 17685c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka final int keyX, keyY; 176924ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka if (Constants.isValidCoordinate(x) && Constants.isValidCoordinate(y)) { 17705c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka final KeyDetector keyDetector = 177127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mKeyboardSwitcher.getMainKeyboardView().getKeyDetector(); 17725c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyX = keyDetector.getTouchX(x); 17735c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka keyY = keyDetector.getTouchY(y); 177424ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka } else { 177524ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka keyX = x; 177624ab8055aaae75bcb80c686efc2046a301ebb6adTadashi G. Takaoka keyY = y; 17775c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka } 17785c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka mWordComposer.add(primaryCode, keyX, keyY); 17795475b38328171a0841ae18074bd45380ec567e90Jean Chalard // If it's the first letter, make note of auto-caps state 17805475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (mWordComposer.size() == 1) { 1781adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode()); 1782923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 17835475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1784923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1785e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, 1786ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka spaceState, Constants.SUGGESTION_STRIP_COORDINATE == x); 1787863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 17887a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 1789e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1790e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (swapWeakSpace) { 1791bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 1792e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard mSpaceState = SPACE_STATE_WEAK; 1793e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 17948f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // In case the "add to dictionary" hint was still displayed. 17954702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (null != mSuggestionStripView) mSuggestionStripView.dismissAddToDictionaryHint(); 1796e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1797a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 179887cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 179987cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Utils.Stats.onNonSeparator((char)primaryCode, x, y); 180087cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 1801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1803c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard // Returns true if we did an autocorrection, false otherwise. 1804c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard private boolean handleSeparator(final int primaryCode, final int x, final int y, 1805120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState) { 1806c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Handle separator 1808196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 18098ee4b35c7010c6e8f792e49a88dc4e908f7230fcJean Chalard if (mCurrentSettings.mCorrectionEnabled) { 1810a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard // TODO: maybe cache Strings in an <String> sparse array or something 1811a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard commitCurrentAutoCorrection(new String(new int[]{primaryCode}, 0, 1)); 1812c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = true; 1813923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1814a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard commitTyped(new String(new int[]{primaryCode}, 0, 1)); 1815923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 18174ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1818e091982868476845acbcc8eff2ae3cad6de8776cJean Chalard final boolean swapWeakSpace = maybeStripSpace(primaryCode, spaceState, 1819ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka Constants.SUGGESTION_STRIP_COORDINATE == x); 1820863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 182100ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1822297e6d590bd957577c335aa8713a786145a70288Jean Chalard mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { 18230e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 182400ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard } 18257a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 182689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 1827240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_SPACE == primaryCode) { 1828fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard if (mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { 18292b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa if (maybeDoubleSpacePeriod()) { 1830120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_DOUBLE; 1831120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else if (!isShowingPunctuationList()) { 1832120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_WEAK; 1833120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1834126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 1835120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 18362b6a1fed767080aaa71acbd591d30b9f436b0499Ken Wakasa mHandler.startDoubleSpacePeriodTimer(); 1837297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (!mConnection.isCursorTouchingWord(mCurrentSettings)) { 1838a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 183989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 184089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1841fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (swapWeakSpace) { 1842bbbdab12be748cdc2158f0e04bbb5478052ecd89Jean Chalard swapSwapperAndSpace(); 18434721427c7de3600f6fe7dfff16508a6a974fb3e4Jean Chalard mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; 1844f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard } else if (SPACE_STATE_PHANTOM == spaceState 18457e4ad33a655a3b7fdaf45163a93bc5ac0d0ea696Jean Chalard && !mCurrentSettings.isWeakSpaceStripper(primaryCode) 18467e4ad33a655a3b7fdaf45163a93bc5ac0d0ea696Jean Chalard && !mCurrentSettings.isPhantomSpacePromotingSymbol(primaryCode)) { 1847fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // If we are in phantom space state, and the user presses a separator, we want to 1848fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // stay in phantom space state so that the next keypress has a chance to add the 1849fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // space. For example, if I type "Good dat", pick "day" from the suggestion strip 1850fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // then insert a comma and go on to typing the next word, I want the space to be 1851fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // inserted automatically before the next word, the same way it is when I don't 1852fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // input the comma. 1853f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // The case is a little different if the separator is a space stripper. Such a 1854f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // separator does not normally need a space on the right (that's the difference 1855f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // between swappers and strippers), so we should not stay in phantom space state if 1856f68fe7a9c9262a3591eeba61f34a91855a34c930Jean Chalard // the separator is a stripper. Hence the additional test above. 1857fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1858120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1859120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 186089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Set punctuation right away. onUpdateSelection will fire but tests whether it is 186189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // already displayed or not, so it's okay. 186255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka setPunctuationSuggestions(); 1863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 186487cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 186587cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Utils.Stats.onSeparator((char)primaryCode, x, y); 186687cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 1867120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1868fff8613df04af17bf56db866075b220d1ef0fbe8Jean Chalard mKeyboardSwitcher.updateShiftState(); 1869c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard return didAutoCorrect; 1870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1871466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1872bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private CharSequence getTextWithUnderline(final String text) { 18730a59ac2ba88ac1f99151d9336136bc6fe7d416c0Jean Chalard return mIsAutoCorrectionIndicatorOn 187477d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) 1875fda847a870829f1491cbd5325f9c985213081149Jean Chalard : text; 187677d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 187777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard 1878923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void handleClose() { 18795475b38328171a0841ae18074bd45380ec567e90Jean Chalard commitTyped(LastComposedWord.NOT_A_SEPARATOR); 1880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestHideSelf(0); 188127e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView(); 188227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mainKeyboardView != null) { 188327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka mainKeyboardView.closing(); 18840a524de3df86e3039acba40b69ccba67ec484a41Tadashi G. Takaoka } 1885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1887a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // TODO: make this private 1888a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Outside LatinIME, only used by the test suite. 188915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting 18909fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka boolean isShowingPunctuationList() { 18914702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView == null) return false; 18924702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka return mCurrentSettings.mSuggestPuncList == mSuggestionStripView.getSuggestions(); 18937599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 18947599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1895a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private boolean isSuggestionsStripVisible() { 18964702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView == null) 1897b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa return false; 18984702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView.isShowingAddToDictionaryHint()) 18999fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 19003d44f489b321f7586af4af8f281550a45653f50aJean Chalard if (!mCurrentSettings.isSuggestionStripVisibleInOrientation(mDisplayOrientation)) 19019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return false; 1902dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (mCurrentSettings.isApplicationSpecifiedCompletionsOn()) 19039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 1904fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard return mCurrentSettings.isSuggestionsRequested(mDisplayOrientation); 1905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1907259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka private void clearSuggestionStrip() { 1908259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(SuggestedWords.EMPTY, false); 19097204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1910466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1911466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1912259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka private void setSuggestionStrip(final SuggestedWords words, final boolean isAutoCorrection) { 19134702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) { 19144702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.setSuggestions(words); 1915dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection); 1916466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1917d02783cb63293507e8544ea60d07559092ce83d4Jean Chalard } 1918ec780e2868962bf17f0dfd35d36895f543bde40asatok 191938e535e59676ac4d7bf27026fe3e16fcd9eb292eJean Chalard private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { 1920ec780e2868962bf17f0dfd35d36895f543bde40asatok // Put a blue underline to a word in TextView which will be auto-corrected. 19212be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator 19222be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard && mWordComposer.isComposingWord()) { 19232be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; 19242be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard final CharSequence textWithUnderline = 19252be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard getTextWithUnderline(mWordComposer.getTypedWord()); 1926574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // TODO: when called from an updateSuggestionStrip() call that results from a posted 1927574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // message, this is called outside any batch edit. Potentially, this may result in some 1928574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // janky flickering of the screen, although the display speed makes it unlikely in 1929574b80aacee95df26e85e6b78876a73d7076a672Jean Chalard // the practice. 19305475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(textWithUnderline, 1); 1931ec780e2868962bf17f0dfd35d36895f543bde40asatok } 1932466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1933466741d8a78965b8509bf527344f289e50873092Mike LeBeau 19347575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka private void updateSuggestionStrip() { 1935d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard mHandler.cancelUpdateSuggestionStrip(); 1936305326e789c3a89517855cc5a023ed1aa3074dc0Jean Chalard 1937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Check if we have a suggestion engine attached. 19387ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard if (mSuggest == null || !mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)) { 1939edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard if (mWordComposer.isComposingWord()) { 19407ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard Log.w(TAG, "Called updateSuggestionsOrPredictions but suggestions were not " 19417ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard + "requested!"); 1942edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 1943edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 19447575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return; 1945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1946466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1947e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) { 1948e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard setPunctuationSuggestions(); 19497575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return; 1950e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard } 1951e4498929b070cdd673c69450e316e2932e334fd5Jean Chalard 1952f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka final SuggestedWords suggestedWords = getSuggestedWords(Suggest.SESSION_TYPING); 19537575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 19547575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka showSuggestionStrip(suggestedWords, typedWord); 19557575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka } 19567575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka 1957f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private SuggestedWords getSuggestedWords(final int sessionId) { 1958d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 1959c7318bbc0b47662799d2f7a01e5b53edb43ebf2aTadashi G. Takaoka if (keyboard == null || mSuggest == null) { 1960d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka return SuggestedWords.EMPTY; 1961d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka } 19627575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final String typedWord = mWordComposer.getTypedWord(); 196332f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // Get the word on which we should search the bigrams. If we are composing a word, it's 196432f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we 196532f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // should just skip whitespace if any, so 1. 196632f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // TODO: this is slow (2-way IPC) - we should probably cache this instead. 1967bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String prevWord = 196832f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 196932f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard mWordComposer.isComposingWord() ? 2 : 1); 19707575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, 1971d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka prevWord, keyboard.getProximityInfo(), mCurrentSettings.mCorrectionEnabled, 1972d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka sessionId); 19737575ac70546c6a19331102a7719337614f5e3a0fTadashi G. Takaoka return maybeRetrieveOlderSuggestions(typedWord, suggestedWords); 19747ed22f1f72dfa14b13ad6775617fd9e89f0ca224Jean Chalard } 1975979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1976bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private SuggestedWords maybeRetrieveOlderSuggestions(final String typedWord, 197732f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard final SuggestedWords suggestedWords) { 197832f5384fc955f1e9fa8613ca86081f1bf4ccc421Jean Chalard // TODO: consolidate this into getSuggestedWords 197909fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // We update the suggestion strip only when we have some suggestions to show, i.e. when 198009fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // the suggestion count is > 1; else, we leave the old suggestions, with the typed word 198109fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // replaced with the new one. However, when the word is a dictionary word, or when the 198209fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // length of the typed word is 1 or 0 (after a deletion typically), we do want to remove the 198309fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // old suggestions. Also, if we are showing the "add to dictionary" hint, we need to 198409fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard // revert to suggestions - although it is unclear how we can come here if it's displayed. 198509fdd30e5261990ace636c52a8330d4c5dbb364bJean Chalard if (suggestedWords.size() > 1 || typedWord.length() <= 1 1986f4267c052160d8865399a758ce9d60916ed783ecJean Chalard || !suggestedWords.mTypedWordValid 19874702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka || mSuggestionStripView.isShowingAddToDictionaryHint()) { 1988ea80794dd43d44fe53884b4b8f4567af3d0e8331Jean Chalard return suggestedWords; 1989838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard } else { 19904702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka SuggestedWords previousSuggestions = mSuggestionStripView.getSuggestions(); 1991297e6d590bd957577c335aa8713a786145a70288Jean Chalard if (previousSuggestions == mCurrentSettings.mSuggestPuncList) { 1992838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard previousSuggestions = SuggestedWords.EMPTY; 1993fe1a6d961cf039357f061482461e4d2e951ad346satok } 19944ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = 199588bf1ba5263f5a5c1df367ddc401db4109ef8677Jean Chalard SuggestedWords.getTypedWordAndPreviousSuggestions( 19964ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard typedWord, previousSuggestions); 1997ea80794dd43d44fe53884b4b8f4567af3d0e8331Jean Chalard return new SuggestedWords(typedWordAndPreviousSuggestions, 19982e2519ee914d4bf9462950553840557a4c19faedJean Chalard false /* typedWordValid */, 1999bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard false /* hasAutoCorrectionCandidate */, 200003a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isPunctuationSuggestions */, 20010142b997bf18f5d07e83b3fd403f0b3ea4736040satok true /* isObsoleteSuggestions */, 20020142b997bf18f5d07e83b3fd403f0b3ea4736040satok false /* isPrediction */); 20039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka } 2004979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 20054a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 2006bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private void showSuggestionStrip(final SuggestedWords suggestedWords, final String typedWord) { 2007c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka if (suggestedWords.isEmpty()) { 2008259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 20092c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard return; 20102c5cf744e554cbe0872f1b3e18cbd1383b0189f9Jean Chalard } 2011bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String autoCorrection; 2012c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka if (suggestedWords.mWillAutoCorrect) { 2013c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka autoCorrection = suggestedWords.getWord(1); 2014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 2015c6ff7c42d9aeafe2b2d21a34be10f1e9a450153aTadashi G. Takaoka autoCorrection = typedWord; 2016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2017d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard mWordComposer.setAutoCorrection(autoCorrection); 20189b01890254c62a30b079bd9f79a30f9541faf11bJean Chalard final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); 2019259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(suggestedWords, isAutoCorrection); 2020dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 2021913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 2022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2024a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard private void commitCurrentAutoCorrection(final String separatorString) { 2025913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Complete any pending suggestions query first 2026d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka if (mHandler.hasPendingUpdateSuggestions()) { 2027259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka updateSuggestionStrip(); 2028923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2029bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); 2030eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang final String typedWord = mWordComposer.getTypedWord(); 2031bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String autoCorrection = (typedAutoCorrection != null) 2032eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang ? typedAutoCorrection : typedWord; 2033117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard if (autoCorrection != null) { 203446798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard if (TextUtils.isEmpty(typedWord)) { 203546798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard throw new RuntimeException("We have an auto-correction but the typed word " 203646798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard + "is empty? Impossible! I must commit suicide."); 203746798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard } 203887cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 203987cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onAutoCorrection( 204087cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka typedWord, autoCorrection.toString(), separatorString, mWordComposer); 204187cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 20424733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 204366bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, 2044a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard separatorString); 20455475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!typedWord.equals(autoCorrection)) { 20461c6cf26c3705e845418a29718c034598b52293ccJean Chalard // This will make the correction flash for a short while as a visual clue 204728d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // to the user that auto-correction happened. It has no other effect; in particular 204828d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // note that this won't affect the text inside the text field AT ALL: it only makes 204928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // the segment of text starting at the supplied index and running for the length 205028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // of the auto-correction flash. At this moment, the "typedWord" argument is 205128d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard // ignored by TextView. 20525475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCorrection( 20535475b38328171a0841ae18074bd45380ec567e90Jean Chalard new CorrectionInfo(mLastSelectionEnd - typedWord.length(), 205496fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasa typedWord, autoCorrection)); 20551c6cf26c3705e845418a29718c034598b52293ccJean Chalard } 2056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 20594702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener} 20604702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka // interface 2061c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 2062bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void pickSuggestionManually(final int index, final String suggestion) { 20634702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); 2064551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput 2065551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard if (suggestion.length() == 1 && isShowingPunctuationList()) { 2066551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Word separators are suggested before the user inputs something. 2067551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // So, LatinImeLogger logs "" as a user's input. 2068551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); 2069551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. 2070551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard final int primaryCode = suggestion.charAt(0); 2071551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard onCodeInput(primaryCode, 2072ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaoka Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE); 207394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 207494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_punctuationSuggestion(index, suggestion); 207594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 2076551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard return; 2077551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard } 2078551612dd9ec79c9f9a7e430801fdf430dfe625e9Jean Chalard 20794fde56b8182514bcae64d76488724d2a64a73f14Jean Chalard mConnection.beginBatchEdit(); 2080eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0 2081eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // In the batch input mode, a manually picked suggested word should just replace 2082eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang // the current batch input text and there is no need for a phantom space. 2083eea34598bf63f670f47d7b3f37b6436921e5fe02Tom Ouyang && !mWordComposer.isBatchMode()) { 2084845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard int firstChar = Character.codePointAt(suggestion, 0); 2085297e6d590bd957577c335aa8713a786145a70288Jean Chalard if ((!mCurrentSettings.isWeakSpaceStripper(firstChar)) 2086297e6d590bd957577c335aa8713a786145a70288Jean Chalard && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) { 20870e84041bf740590230198fa845d8c45acd4cb586Jean Chalard promotePhantomSpace(); 2088845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 2089845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 2090845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard 2091dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard if (mCurrentSettings.isApplicationSpecifiedCompletionsOn() 2092dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mApplicationSpecifiedCompletions != null 20931b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka && index >= 0 && index < mApplicationSpecifiedCompletions.length) { 20944702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka if (mSuggestionStripView != null) { 20954702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.clear(); 2096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2097b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 2098611a5bdf650f7bc54bf40176f84f1cd9c87aa9aaJean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 20995475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; 21005475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.commitCompletion(completionInfo); 21019d71748ba48dbc8793f3e1ecddf5fd31b8e59613Jean Chalard mConnection.endBatchEdit(); 2102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 2103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 21046a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 2105af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // We need to log before we commit, because the word composer will store away the user 2106af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // typed word. 21079bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge final String replacedWord = mWordComposer.getTypedWord().toString(); 21089bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge LatinImeLogger.logOnManualSuggestion(replacedWord, 21098cc8f26adfe0f06cebc697dac43a856326cf7afcTadashi G. Takaoka suggestion.toString(), index, suggestedWords); 211035c11842a78e272ac4f61bfc58b96826c833f104Kurt Partridge mExpectingUpdateSelection = true; 211135c11842a78e272ac4f61bfc58b96826c833f104Kurt Partridge commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, 211235c11842a78e272ac4f61bfc58b96826c833f104Kurt Partridge LastComposedWord.NOT_A_SEPARATOR); 211394e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 211494e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge ResearchLogger.latinIME_pickSuggestionManually(replacedWord, index, suggestion); 211594e7f4bef970431f509a806d1b92b19fc3b5ce7dKurt Partridge } 21164fde56b8182514bcae64d76488724d2a64a73f14Jean Chalard mConnection.endBatchEdit(); 211729a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard // Don't allow cancellation of manual pick 211829a1fc0f6b18dd41e7810ee720041f7c7557eb4fJean Chalard mLastComposedWord.deactivate(); 211990a91272447fd64bc54e06f08f45b11c45930767Jean Chalard // Space state must be updated before calling updateShiftState 2120fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 2121fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mKeyboardSwitcher.updateShiftState(); 2122979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2123c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // We should show the "Touch again to save" hint if the user pressed the first entry 2124491d451e382a8e7d42937a96e4e06ada483e57b5Jean Chalard // AND it's in none of our current dictionaries (main, user or otherwise). 21257f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // Please note that if mSuggest is null, it means that everything is off: suggestion 21267f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // and correction, so we shouldn't try to show the hint 2127bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null 2128491d451e382a8e7d42937a96e4e06ada483e57b5Jean Chalard // If the suggestion is not in the dictionary, the hint should be shown. 2129491d451e382a8e7d42937a96e4e06ada483e57b5Jean Chalard && !AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(), suggestion, true); 2130b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 213187cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 2132240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka Stats.onSeparator((char)Constants.CODE_SPACE, 213387cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 213487cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 2135b1dc8ad5f244337f91fcdac2a17078f5b9239cb7Jean Chalard if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) { 21364702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripView.showAddToDictionaryHint( 21374702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka suggestion, mCurrentSettings.mHintToSaveText); 2138b1dc8ad5f244337f91fcdac2a17078f5b9239cb7Jean Chalard } else { 21398f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // If we're not showing the "Touch again to save", then update the suggestion strip. 2140a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 214166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 2142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2143a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2144979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 21458558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa * Commits the chosen word to the text field and saves it for later retrieval. 2146979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 2147bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private void commitChosenWord(final String chosenWord, final int commitType, 2148a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard final String separatorString) { 21494702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final SuggestedWords suggestedWords = mSuggestionStripView.getSuggestions(); 2150e8bb8351d6f09f461851af619cabe5fcd2f66c0aJean Chalard mConnection.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( 2151e8bb8351d6f09f461851af619cabe5fcd2f66c0aJean Chalard this, chosenWord, suggestedWords, mIsMainDictionaryAvailable), 1); 2152c54d558e2e70bdfb2c1078cae7b88440d421dc67satok // Add the word to the user history dictionary 2153bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String prevWord = addToUserHistoryDictionary(chosenWord); 21540fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // TODO: figure out here if this is an auto-correct or if the best word is actually 21550fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // what user typed. Note: currently this is done much later in 2156bdf89ce5feedb03e67b43f530b1eb9bd44203c63Jean Chalard // LastComposedWord#didCommitTypedWord by string equality of the remembered 21570fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // strings. 2158c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mLastComposedWord = mWordComposer.commitWord(commitType, chosenWord.toString(), 2159a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard separatorString, prevWord); 2160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2162a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard private void setPunctuationSuggestions() { 2163a19c5e63804e6cffac5771b9749aad6c441e5e21Jean Chalard if (mCurrentSettings.mBigramPredictionEnabled) { 2164259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka clearSuggestionStrip(); 2165d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard } else { 2166259905ba901add520de56715200fb67fab818764Tadashi G. Takaoka setSuggestionStrip(mCurrentSettings.mSuggestPuncList, false); 2167d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard } 21687204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 2169913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 21706a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 21716a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 2172bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka private String addToUserHistoryDictionary(final String suggestion) { 2173c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (TextUtils.isEmpty(suggestion)) return null; 2174e46d12927ee2717788248b05f00b751beaf2a02aKen Wakasa if (mSuggest == null) return null; 2175bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 2176ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // If correction is not enabled, we don't add words to the user history dictionary. 2177ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // That's to avoid unintended additions in some sensitive fields, or fields that 2178ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard // expect to receive non-words. 2179ca6b7d52650917b92bf00e092ddad25d9f3f2537Jean Chalard if (!mCurrentSettings.mCorrectionEnabled) return null; 2180bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 218167b9337b6cc478973d2c628fb5686583ce339bf0Satoshi Kataoka final UserHistoryDictionary userHistoryDictionary = mUserHistoryDictionary; 218267b9337b6cc478973d2c628fb5686583ce339bf0Satoshi Kataoka if (userHistoryDictionary != null) { 218302308bec632a5df23325c916bffec5def16b22b4Jean Chalard final CharSequence prevWord 2184d579f1aefc8d02254db297ffd6d8f9dbdcab0637Jean Chalard = mConnection.getNthPreviousWord(mCurrentSettings.mWordSeparators, 2); 218571f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard final String secondWord; 2186adbd9ae105e06287b59379d7f7127d95fd0663f4Jean Chalard if (mWordComposer.wasAutoCapitalized() && !mWordComposer.isMostlyCaps()) { 2187bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka secondWord = suggestion.toLowerCase(mSubtypeSwitcher.getCurrentSubtypeLocale()); 218871f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } else { 2189bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka secondWord = suggestion; 219071f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } 219168c650fb2a3b26d4000e849f96f0664598c95470Satoshi Kataoka // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid". 219268c650fb2a3b26d4000e849f96f0664598c95470Satoshi Kataoka // We don't add words with 0-frequency (assuming they would be profanity etc.). 2193c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka final int maxFreq = AutoCorrection.getMaxFrequency( 2194c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka mSuggest.getUnigramDictionaries(), suggestion); 219568c650fb2a3b26d4000e849f96f0664598c95470Satoshi Kataoka if (maxFreq == 0) return null; 2196bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String prevWordString = (null == prevWord) ? null : prevWord.toString(); 2197bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka userHistoryDictionary.addToUserHistory(prevWordString, secondWord, maxFreq > 0); 2198bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka return prevWordString; 219932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 2200c54d558e2e70bdfb2c1078cae7b88440d421dc67satok return null; 220132e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 220232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani 22036b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 22046b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Check if the cursor is actually at the end of a word. If so, restart suggestions on this 22056b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * word, else do nothing. 22066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 22075475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() { 2208747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard final CharSequence word = mConnection.getWordBeforeCursorIfAtEndOfWord(mCurrentSettings); 2209747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard if (null != word) { 2210747cf0435a7e978dfd43c30bd931b56146c3d852Jean Chalard restartSuggestionsOnWordBeforeCursor(word); 2211fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard } 22126b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 22136b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 22145475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void restartSuggestionsOnWordBeforeCursor(final CharSequence word) { 22153708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); 2216d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int length = word.length(); 22175475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(length, 0); 22185475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.setComposingText(word, 1); 2219a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 22206b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 22216b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 22225475b38328171a0841ae18074bd45380ec567e90Jean Chalard private void revertCommit() { 2223bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String previousWord = mLastComposedWord.mPrevWord; 2224b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard final String originallyTypedWord = mLastComposedWord.mTypedWord; 2225bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String committedWord = mLastComposedWord.mCommittedWord; 2226cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final int cancelLength = committedWord.length(); 2227ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok final int separatorLength = LastComposedWord.getSeparatorLength( 2228a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mLastComposedWord.mSeparatorString); 2229193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // TODO: should we check our saved separator against the actual contents of the text view? 2230d442984e96cc6299c905141e3e32e0a4f55394c8Kurt Partridge final int deleteLength = cancelLength + separatorLength; 2231890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2232b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard if (mWordComposer.isComposingWord()) { 22335935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit, but we are composing a word"); 2234b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard } 2235bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final CharSequence wordBeforeCursor = 22365475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.getTextBeforeCursor(deleteLength, 0) 2237bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka .subSequence(0, cancelLength); 2238cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard if (!TextUtils.equals(committedWord, wordBeforeCursor)) { 22395935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit check failed: we thought we were " 2240cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard + "reverting \"" + committedWord 2241890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); 2242890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 22438558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa } 22445475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(deleteLength, 0); 2245c54d558e2e70bdfb2c1078cae7b88440d421dc67satok if (!TextUtils.isEmpty(previousWord) && !TextUtils.isEmpty(committedWord)) { 2246c54d558e2e70bdfb2c1078cae7b88440d421dc67satok mUserHistoryDictionary.cancelAddingUserHistory( 2247c54d558e2e70bdfb2c1078cae7b88440d421dc67satok previousWord.toString(), committedWord.toString()); 2248c54d558e2e70bdfb2c1078cae7b88440d421dc67satok } 2249a05a0f20776b4c33f41f043f1bff245331937580Jean Chalard mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1); 225087cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka if (ProductionFlag.IS_INTERNAL) { 225187cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Stats.onSeparator(mLastComposedWord.mSeparatorString, 225287cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); 225387cecf7db61536d9f7ec07fe198d37a11b6c8407Satoshi Kataoka } 22540e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard if (ProductionFlag.IS_EXPERIMENTAL) { 22550e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard ResearchLogger.latinIME_revertCommit(originallyTypedWord); 2256193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } 22570e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // Don't restart suggestion yet. We'll restart if the user deletes the 22580e9e7e337defe97d4ede8c59d0e925f5401f9292Jean Chalard // separator. 2259b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 2260746e014eb54f0d6278b948868dff4863bfe85ad8Jean Chalard // We have a separator between the word and the cursor: we should show predictions. 2261a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 2262890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2263890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 22640e84041bf740590230198fa845d8c45acd4cb586Jean Chalard // This essentially inserts a space, and that's it. 22650e84041bf740590230198fa845d8c45acd4cb586Jean Chalard public void promotePhantomSpace() { 2266ec60d60078b4837b657dc207bdbde1748749199eJean Chalard if (mCurrentSettings.shouldInsertSpacesAutomatically()) { 2267e36af707c8a8705ebd19fcc359c51181f7ebd171Jean Chalard sendKeyCodePoint(Constants.CODE_SPACE); 2268ec60d60078b4837b657dc207bdbde1748749199eJean Chalard } 22690e84041bf740590230198fa845d8c45acd4cb586Jean Chalard } 22700e84041bf740590230198fa845d8c45acd4cb586Jean Chalard 2271a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Used by the RingCharBuffer 2272f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public boolean isWordSeparator(final int code) { 2273297e6d590bd957577c335aa8713a786145a70288Jean Chalard return mCurrentSettings.isWordSeparator(code); 2274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22769fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka // TODO: Make this private 22779fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka // Outside LatinIME, only used by the {@link InputTestsBase} test suite. 227815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka @UsedForTesting 22799fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka void loadKeyboard() { 22801e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // When the device locale is changed in SetupWizard etc., this method may get called via 22811e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // onConfigurationChanged before SoftInputWindow is shown. 22820657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka initSuggest(); 22830657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka loadSettings(); 228427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (mKeyboardSwitcher.getMainKeyboardView() != null) { 22851e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // Reload keyboard because the current language has been changed. 2286297e6d590bd957577c335aa8713a786145a70288Jean Chalard mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mCurrentSettings); 22871e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka } 2288b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // Since we just changed languages, we should re-evaluate suggestions with whatever word 2289b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // we are currently composing. If we are not composing anything, we may want to display 22908f9c9377fc8944c9e96e6dcf661f0d673c23b83fJean Chalard // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway). 2291a6757f400a7a1acc66b2c64f4aa84137dd4395cdJean Chalard mHandler.postUpdateSuggestionStrip(); 229236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 229336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 2294a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback called by PointerTracker through the KeyboardActionListener. This is called when a 2295a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // key is depressed; release matching call is onReleaseKey below. 22965a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 2297f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onPressKey(final int primaryCode) { 2298a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mKeyboardSwitcher.onPressKey(primaryCode); 2299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2301a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Callback by PointerTracker through the KeyboardActionListener. This is called when a key 2302a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // is released; press matching call is onPressKey above. 23035a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 2304f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onReleaseKey(final int primaryCode, final boolean withSliding) { 23052a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); 23068d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 23078d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv // If accessibility is on, ensure the user receives keyboard state updates. 23088d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 23098d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (primaryCode) { 2310240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SHIFT: 23118d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); 23128d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 2313240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SWITCH_ALPHA_SYMBOL: 23148d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); 23158d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 23168d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 23178d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2318978c96aa995015658070346b60826a3a34fdaf84Jean Chalard 2319240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka if (Constants.CODE_DELETE == primaryCode) { 2320978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // This is a stopgap solution to avoid leaving a high surrogate alone in a text view. 2321978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // In the future, we need to deprecate deteleSurroundingText() and have a surrogate 2322978c96aa995015658070346b60826a3a34fdaf84Jean Chalard // pair-friendly way of deleting characters in InputConnection. 2323e91d495c53a2606962159cfddada2b7a5e206c4cJean Chalard // TODO: use getCodePointBeforeCursor instead to improve performance 23245475b38328171a0841ae18074bd45380ec567e90Jean Chalard final CharSequence lastChar = mConnection.getTextBeforeCursor(1, 0); 23255475b38328171a0841ae18074bd45380ec567e90Jean Chalard if (!TextUtils.isEmpty(lastChar) && Character.isHighSurrogate(lastChar.charAt(0))) { 23265475b38328171a0841ae18074bd45380ec567e90Jean Chalard mConnection.deleteSurroundingText(1, 0); 2327978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2328978c96aa995015658070346b60826a3a34fdaf84Jean Chalard } 2329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2330a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2331123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka // receive ringer mode change and network state change. 2332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private BroadcastReceiver mReceiver = new BroadcastReceiver() { 2333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 2334f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void onReceive(final Context context, final Intent intent) { 2335123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final String action = intent.getAction(); 2336564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2337123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka mSubtypeSwitcher.onNetworkStateChanged(intent); 233821af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 23398e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka mKeyboardSwitcher.onRingerModeChanged(); 2340123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } 2341923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2342923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 2343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2344c206d0462354b3bf1ad0cec61534da567829555dTadashi G. Takaoka private void launchSettings() { 23453c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge handleClose(); 23463c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(SettingsActivity.class); 2347466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2348466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2349a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard // Called from debug code only 2350bf96661d33d0126adb60a48880ceba1ff055d4a4satok public void launchDebugSettings() { 23513c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge handleClose(); 23523c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(DebugSettingsActivity.class); 2353bf96661d33d0126adb60a48880ceba1ff055d4a4satok } 2354bf96661d33d0126adb60a48880ceba1ff055d4a4satok 2355f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void launchKeyboardedDialogActivity(final Class<? extends Activity> activityClass) { 23563c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge // Put the text in the attached EditText into a safe, saved state before switching to a 23573c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge // new activity that will also use the soft keyboard. 23583c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge commitTyped(LastComposedWord.NOT_A_SEPARATOR); 23593c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge launchSubActivity(activityClass); 23603c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge } 23613c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge 2362f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka private void launchSubActivity(final Class<? extends Activity> activityClass) { 2363923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Intent intent = new Intent(); 23643c233bf1a5003c478a27964758afe2ca581d3d8bKurt Partridge intent.setClass(LatinIME.this, activityClass); 2365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project startActivity(intent); 2367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 23692fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showSubtypeSelectorAndSettings() { 237085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 237185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 237285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka // TODO: Should use new string "Select active input modes". 237385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.language_selection_title), 237485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.english_ime_settings), 237585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 237685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 23772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka @Override 23782fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka public void onClick(DialogInterface di, int position) { 23792fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka di.dismiss(); 23802fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka switch (position) { 238185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 23822cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok Intent intent = CompatUtils.getInputLanguageSelectionIntent( 23836fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mRichImm.getInputMethodIdOfThisIme(), 23842a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Intent.FLAG_ACTIVITY_NEW_TASK 23852fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 23862fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 23872fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka startActivity(intent); 23882fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2389aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa case 1: 2390aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa launchSettings(); 2391aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa break; 23922fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 23932fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 239485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2395bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2396bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2397bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2398724bc479f7d796d6ce5d5e200216bea855b818b2Kurt Partridge showOptionDialog(builder.create()); 23992fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 2400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2401f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka public void showOptionDialog(final AlertDialog dialog) { 240227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka final IBinder windowToken = mKeyboardSwitcher.getMainKeyboardView().getWindowToken(); 240327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka if (windowToken == null) { 240427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka return; 240527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka } 240613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 240713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCancelable(true); 240813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCanceledOnTouchOutside(true); 240913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 241013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final Window window = dialog.getWindow(); 241113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final WindowManager.LayoutParams lp = window.getAttributes(); 241213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.token = windowToken; 241313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 241413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.setAttributes(lp); 241513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 241613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 241713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka mOptionsDialog = dialog; 241813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.show(); 241913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka } 242013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 242128d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard public void debugDumpStateAndCrashWithException(final String context) { 242228d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard final StringBuilder s = new StringBuilder(); 242328d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard s.append("Target application : ").append(mTargetApplicationInfo.name) 242428d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard .append("\nPackage : ").append(mTargetApplicationInfo.packageName) 242528d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard .append("\nTarget app sdk version : ") 242628d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard .append(mTargetApplicationInfo.targetSdkVersion) 242728d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard .append("\nAttributes : ").append(mCurrentSettings.getInputAttributesDebugString()) 242828d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard .append("\nContext : ").append(context); 242928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard throw new RuntimeException(s.toString()); 243028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard } 243128d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard 24327e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 2433f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka protected void dump(final FileDescriptor fd, final PrintWriter fout, final String[] args) { 2434923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.dump(fd, fout, args); 2435a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2436923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project final Printer p = new PrintWriterPrinter(fout); 2437923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println("LatinIME state :"); 24383708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2439df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; 2440df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka p.println(" Keyboard mode = " + keyboardMode); 2441fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard p.println(" mIsSuggestionsSuggestionsRequested = " 2442fe53e5c060dc4fd0acdfdffcadba94f9bb6062c3Jean Chalard + mCurrentSettings.isSuggestionsRequested(mDisplayOrientation)); 24432f3a694e29ad5a63052a2f963327855fee099f55Jean Chalard p.println(" mCorrectionEnabled=" + mCurrentSettings.mCorrectionEnabled); 24444d0f03bd66742ee292da81a3e025e119f28b6940Jean Chalard p.println(" isComposingWord=" + mWordComposer.isComposingWord()); 2445297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mSoundOn=" + mCurrentSettings.mSoundOn); 2446297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mVibrateOn=" + mCurrentSettings.mVibrateOn); 2447297e6d590bd957577c335aa8713a786145a70288Jean Chalard p.println(" mKeyPreviewPopupOn=" + mCurrentSettings.mKeyPreviewPopupOn); 2448dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard p.println(" inputAttributes=" + mCurrentSettings.getInputAttributesDebugString()); 2449923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2450923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 2451