LatinIME.java revision 60adb8757496fecb8f376a80832c176b35e43d06
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 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog; 20923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver; 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface; 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent; 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter; 25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences; 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration; 2736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources; 28c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.graphics.Rect; 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService; 30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager; 31123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager; 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug; 3381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaokaimport android.os.IBinder; 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 36bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager; 38e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType; 39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils; 40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log; 41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 458e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup; 46c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaokaimport android.view.ViewGroup.LayoutParams; 47cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokaimport android.view.ViewParent; 4813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.Window; 4913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.WindowManager; 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo; 5196fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasaimport android.view.inputmethod.CorrectionInfo; 52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo; 53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection; 549cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 55c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils; 578d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanvimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 58c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils; 59c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper; 601fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils; 61c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 62c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 636b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 65f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 66c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView; 6716c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaokaimport com.android.inputmethod.latin.LocaleUtils.RunInLocale; 68c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasaimport com.android.inputmethod.latin.define.ProductionFlag; 698c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionsView; 70923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 71466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor; 72466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter; 734ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalardimport java.util.ArrayList; 74466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale; 75466741d8a78965b8509bf527344f289e50873092Mike LeBeau 76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard. 78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 7913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokapublic class LatinIME extends InputMethodService implements KeyboardActionListener, 80913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka SuggestionsView.Listener { 818efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka private static final String TAG = LatinIME.class.getSimpleName(); 82409220583333bdf06290dd9fd42f91b5c0d1b11asatok private static final boolean TRACE = false; 839e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka private static boolean DEBUG; 84a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 858efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka /** 868efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * The private IME option used to indicate that no microphone should be 878efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * shown for a given text field. For instance, this is specified by the 888efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * search dialog when the dialog is already showing a voice search button. 898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * 908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed. 918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka */ 9210dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok @SuppressWarnings("dep-ann") 938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm"; 948efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka 958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka /** 968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * The private IME option used to indicate that no microphone should be 978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * shown for a given text field. For instance, this is specified by the 988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * search dialog when the dialog is already showing a voice search button. 998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka */ 1004199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey"; 1014199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka 1024199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka /** 1034199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka * The private IME option used to indicate that no settings key should be 1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka * shown for a given text field. 1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka */ 1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey"; 1078efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka 108af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka /** 109af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka * The private IME option used to indicate that the given text field needs 110af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka * ASCII code points input. 1111ef6fc7e1519cedec9e84a64968bfba4212d0436Tadashi G. Takaoka * 1121ef6fc7e1519cedec9e84a64968bfba4212d0436Tadashi G. Takaoka * @deprecated Use {@link EditorInfo#IME_FLAG_FORCE_ASCII}. 113af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka */ 1141ef6fc7e1519cedec9e84a64968bfba4212d0436Tadashi G. Takaoka @SuppressWarnings("dep-ann") 115af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka public static final String IME_OPTION_FORCE_ASCII = "forceAscii"; 116af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka 117af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka /** 11811d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka * The subtype extra value used to indicate that the subtype keyboard layout set name. 119af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka */ 12011d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LAYOUT_SET = "KeyboardLayoutSet"; 121af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka 122d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka /** 12311d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka * The subtype extra value used to indicate that the subtype keyboard layout is capable for 12411d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka * typing ASCII characters. 125d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka */ 12611d9ee742f8ff3fb31b0e3beb32ee4870c63d8e3Tadashi G. Takaoka public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable"; 127d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka 1289e347d3d448e48229c46aad394ec9bd60cd5807bsatok private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; 129fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa 130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // How many continuous deletes at which to start deleting at a higher speed. 131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int DELETE_ACCELERATE_AT = 20; 132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Key events coming any faster than this are long-presses. 133d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani private static final int QUICK_PRESS = 200; 134a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 13559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private static final int PENDING_IMS_CALLBACK_DURATION = 800; 136055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 137cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /** 138cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * The name of the scheme used by the Package Manager to warn of a new package installation, 139cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * replacement or removal. 140cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard */ 141cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private static final String SCHEME_PACKAGE = "package"; 142cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 1430fe3611bee5095e7bd0fff2d0fdf8d5a13379132Jean Chalard // TODO: migrate this to SettingsValues 1447599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private int mSuggestionVisibility; 1457599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE 1467599cfea4a2d56f4779452ec8e8742f7b9629cc0satok = R.string.prefs_suggestion_visibility_show_value; 1477599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE 1487599cfea4a2d56f4779452ec8e8742f7b9629cc0satok = R.string.prefs_suggestion_visibility_show_only_portrait_value; 1497599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE 1507599cfea4a2d56f4779452ec8e8742f7b9629cc0satok = R.string.prefs_suggestion_visibility_hide_value; 1517599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1527599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { 1537599cfea4a2d56f4779452ec8e8742f7b9629cc0satok SUGGESTION_VISIBILILTY_SHOW_VALUE, 1547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE, 1557599cfea4a2d56f4779452ec8e8742f7b9629cc0satok SUGGESTION_VISIBILILTY_HIDE_VALUE 1567599cfea4a2d56f4779452ec8e8742f7b9629cc0satok }; 1577599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 158fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_NONE = 0; 159120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Double space: the state where the user pressed space twice quickly, which LatinIME 160120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // resolved as period-space. Undoing this converts the period to a space. 161fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_DOUBLE = 1; 162b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // Swap punctuation: the state where a weak space and a punctuation from the suggestion strip 163b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard // have just been swapped. Undoing this swaps them back; the space is still considered weak. 164120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; 165fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Weak space: a space that should be swapped only by suggestion strip punctuation. Weak 166fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // spaces happen when the user presses space, accepting the current suggestion (whether 167fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // it's an auto-correction or not). 168fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_WEAK = 3; 169fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom space: a not-yet-inserted space that should get inserted on the next input, 170fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // character provided it's not a separator. If it's a separator, the phantom space is dropped. 171fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Phantom spaces happen when a user chooses a word from the suggestion strip. 172fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private static final int SPACE_STATE_PHANTOM = 4; 173120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 174120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Current space state of the input method. This can be any of the above constants. 175120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private int mSpaceState; 176126698fdd256a2e3734634d3b923cabd800064baJean Chalard 1777a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard private SettingsValues mSettingsValues; 17880b66bb166f7f45adfcadcb84788477df9930828Jean Chalard private InputAttributes mInputAttributes; 17917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 180d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka private View mExtractArea; 181abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka private View mKeyPreviewBackingView; 182913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private View mSuggestionsContainer; 183913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private SuggestionsView mSuggestionsView; 184816a8a0fd85ca0327436f8bd1cfa6928600ebc5dJean Chalard /* package for tests */ Suggest mSuggest; 1851b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private CompletionInfo[] mApplicationSpecifiedCompletions; 186a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 187610f1dc8553cf2ed97e763a06a19380c4a6cd636satok private InputMethodManagerCompatWrapper mImm; 1882fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private Resources mResources; 1892fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private SharedPreferences mPrefs; 190109728193e45262099cbf88d8d6fcc4ed05240caJean Chalard /* package for tests */ final KeyboardSwitcher mKeyboardSwitcher; 19189ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard private final SubtypeSwitcher mSubtypeSwitcher; 19281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private boolean mShouldSwitchToLastSubtype = true; 193a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private UserDictionary mUserDictionary; 1959ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard private UserHistoryDictionary mUserHistoryDictionary; 19688562bec54658840dcce352127bdc15705c20a89Jean Chalard private boolean mIsUserDictionaryAvailable; 19736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 1982692a8700737d8eed268039aa27b22a31669da08Jean Chalard private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 1999318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa private WordComposer mWordComposer = new WordComposer(); 200409220583333bdf06290dd9fd42f91b5c0d1b11asatok 20179efbed76f638be298493107fa2d0cd1b5eb529esatok private int mCorrectionMode; 20277da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard 203979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Keep track of the last selection range to decide if we need to show word alternatives 20477da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private static final int NOT_A_CURSOR_POSITION = -1; 20577da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionStart = NOT_A_CURSOR_POSITION; 20677da3d5a3baab0a88f78db5800bb9ede0b39ff60Jean Chalard private int mLastSelectionEnd = NOT_A_CURSOR_POSITION; 207979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2084733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't 2094733609947c0ec74e460bd714fffca0518ade93aJean Chalard // "expect" it, it means the user actually moved the cursor. 2104733609947c0ec74e460bd714fffca0518ade93aJean Chalard private boolean mExpectingUpdateSelection; 211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mDeleteCount; 212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private long mLastKeyTime; 213a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 214564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard private AudioAndHapticFeedbackManager mFeedbackManager; 21528f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 21638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Member variables for remembering the current device orientation. 21738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka private int mDisplayOrientation; 21838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 219cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Object for reacting to adding/removing a dictionary pack. 220cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private BroadcastReceiver mDictionaryPackInstallReceiver = 221cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard new DictionaryPackInstallBroadcastReceiver(this); 222cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 223dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Keeps track of most recently inserted text (multi-character key) for reverting 224dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani private CharSequence mEnteredText; 225dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 22670852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard private boolean mIsAutoCorrectionIndicatorOn; 227604d80c67185954d4691ac775be59c499eee3b1csatok 22813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka private AlertDialog mOptionsDialog; 22913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 2304f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public final UIHandler mHandler = new UIHandler(this); 231d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 2324f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { 23345f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_UPDATE_SHIFT_STATE = 1; 2344c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_SPACE_TYPED = 4; 2354c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_SET_BIGRAM_PREDICTIONS = 5; 2364c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_PENDING_IMS_CALLBACK = 6; 2374c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTIONS = 7; 2384c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka 23910dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateSuggestions; 24010dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateShiftState; 24110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private long mDoubleSpacesTurnIntoPeriodTimeout; 24238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 2434f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UIHandler(LatinIME outerInstance) { 2444f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 24510dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka } 246175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 24710dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka public void onCreate() { 24810dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka final Resources res = getOuterInstance().getResources(); 249175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateSuggestions = 250175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_suggestions); 251175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateShiftState = 252175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_shift_state); 253175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger( 254175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_double_spaces_turn_into_period_timeout); 2554f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 2564f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void handleMessage(Message msg) { 2594f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 2604f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; 261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 262d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SUGGESTIONS: 2634f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.updateSuggestions(); 264d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SHIFT_STATE: 266de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka switcher.updateShiftState(); 267d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 268cb3320179d39a7983874697a0aa428b127675c9dJean Chalard case MSG_SET_BIGRAM_PREDICTIONS: 2694f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.updateBigramPredictions(); 27089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard break; 271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 273d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 274d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void postUpdateSuggestions() { 275d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTIONS); 276175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), mDelayUpdateSuggestions); 277d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 278d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 279d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateSuggestions() { 280d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTIONS); 281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 283d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public boolean hasPendingUpdateSuggestions() { 284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka return hasMessages(MSG_UPDATE_SUGGESTIONS); 285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 287beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka public void postUpdateShiftState() { 288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 289175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); 290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateShiftState() { 293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 294d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 295d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 296cb3320179d39a7983874697a0aa428b127675c9dJean Chalard public void postUpdateBigramPredictions() { 297cb3320179d39a7983874697a0aa428b127675c9dJean Chalard removeMessages(MSG_SET_BIGRAM_PREDICTIONS); 298175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS), mDelayUpdateSuggestions); 29989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 30089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 301cb3320179d39a7983874697a0aa428b127675c9dJean Chalard public void cancelUpdateBigramPredictions() { 302cb3320179d39a7983874697a0aa428b127675c9dJean Chalard removeMessages(MSG_SET_BIGRAM_PREDICTIONS); 30389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 30489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 305fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void startDoubleSpacesTimer() { 306fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka removeMessages(MSG_SPACE_TYPED); 307175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout); 308fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 309fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 310fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void cancelDoubleSpacesTimer() { 311fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka removeMessages(MSG_SPACE_TYPED); 312fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 313fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 314fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public boolean isAcceptingDoubleSpaces() { 315fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka return hasMessages(MSG_SPACE_TYPED); 316fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 31738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 31859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Working variables for the following methods. 31959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mIsOrientationChanging; 3205fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard private boolean mPendingSuccessiveImsCallback; 32159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingStartInput; 32259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInputView; 32359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInput; 324e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private EditorInfo mAppliedEditorInfo; 32559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 32659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void startOrientationChanging() { 327dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka removeMessages(MSG_PENDING_IMS_CALLBACK); 328dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka resetPendingImsCallback(); 32959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = true; 330055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 331f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka if (latinIme.isInputViewShown()) { 332f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka latinIme.mKeyboardSwitcher.saveKeyboardState(); 333f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka } 33459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 33559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 33659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void resetPendingImsCallback() { 33759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = false; 33859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = false; 33959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = false; 34059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 34159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 342e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void executePendingImsCallback(LatinIME latinIme, EditorInfo editorInfo, 34359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka boolean restarting) { 34459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInputView) 34559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(mHasPendingFinishInput); 34659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInput) 34759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 34859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingStartInput) 349e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 35059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka resetPendingImsCallback(); 35159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 35259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 353e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 35459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 35559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the second onStartInput after orientation changed. 35659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = true; 35759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 35859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mIsOrientationChanging && restarting) { 35959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // This is the first onStartInput after orientation changed. 36059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = false; 3615fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = true; 36259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 36359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 364e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 365e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 366055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 367055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 368055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 369e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 3706b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK) 3716b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { 372e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // Typically this is the second onStartInputView after orientation changed. 373e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 374e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } else { 3755fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard if (mPendingSuccessiveImsCallback) { 376e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // This is the first onStartInputView after orientation changed. 3775fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard mPendingSuccessiveImsCallback = false; 378e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 379e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), 380e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka PENDING_IMS_CALLBACK_DURATION); 381e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 382e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 383e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 384e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputViewInternal(editorInfo, restarting); 385e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = editorInfo; 386e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 38759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 38859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 38959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 39059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 39159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInputView after orientation changed. 39259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = true; 39359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 39459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 39559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(finishingInput); 396e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = null; 39738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 39838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 399ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka 40059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 40159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 40259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInput after orientation changed. 40359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = true; 40459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 40559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 40659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka executePendingImsCallback(latinIme, null, false); 40759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 408ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 409ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 41038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 41138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 41289ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard public LatinIME() { 41389ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard super(); 41489ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 41589ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard mKeyboardSwitcher = KeyboardSwitcher.getInstance(); 41689ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard } 41789ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard 4187e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 4197e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka public void onCreate() { 42027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 42127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa mPrefs = prefs; 42227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa LatinImeLogger.init(this, prefs); 423c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 424c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa ResearchLogger.init(this, prefs); 425c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa } 426bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka InputMethodManagerCompatWrapper.init(this); 427ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka SubtypeSwitcher.init(this); 42827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa KeyboardSwitcher.init(this, prefs); 4292ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka AccessibilityUtils.init(this); 430363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 431923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onCreate(); 432363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 433bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka mImm = InputMethodManagerCompatWrapper.getInstance(); 43410dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka mHandler.onCreate(); 4359e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka DEBUG = LatinImeLogger.sDBG; 436363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 437363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka final Resources res = getResources(); 438363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka mResources = res; 439fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard 44028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa loadSettings(); 44128f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 442dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard // TODO: remove the following when it's not needed by updateCorrectionMode() any more 443644c8b7c96627199c13297082e4566adae159bf3Jean Chalard mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */); 4443fe263fac6375836c48ce71da29f098b66eb4f11Jean Chalard updateCorrectionMode(); 4453fe263fac6375836c48ce71da29f098b66eb4f11Jean Chalard 4469502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 447979f8690967ff5409fe18f5085858ccdb8e0ccf1satok boolean tryGC = true; 4489502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 449979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 4500ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 451979f8690967ff5409fe18f5085858ccdb8e0ccf1satok tryGC = false; 452979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (OutOfMemoryError e) { 4539502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e); 454979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 455979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 456979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 457f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = res.getConfiguration().orientation; 458b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 459cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Register to receive ringer mode change and network state change. 460cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Also receive installation and removal of a dictionary pack. 461123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final IntentFilter filter = new IntentFilter(); 462123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 46321af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project registerReceiver(mReceiver, filter); 465cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 466cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final IntentFilter packageFilter = new IntentFilter(); 467cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 468cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 469cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addDataScheme(SCHEME_PACKAGE); 470cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, packageFilter); 471646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard 472646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard final IntentFilter newDictFilter = new IntentFilter(); 473646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard newDictFilter.addAction( 474646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION); 475646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); 476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 47736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 47817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // Has to be package-visible for unit tests 47917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard /* package */ void loadSettings() { 48017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 48116c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka final RunInLocale<SettingsValues> job = new RunInLocale<SettingsValues>() { 48216c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka @Override 48316c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka protected SettingsValues job(Resources res) { 48416c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka return new SettingsValues(mPrefs, LatinIME.this); 48516c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka } 48616c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka }; 48716c6f355700ee5cdaa029f4a25b8b3d40718e6abTadashi G. Takaoka mSettingsValues = job.runInLocale(mResources, mSubtypeSwitcher.getInputLocale()); 48821af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard mFeedbackManager = new AudioAndHapticFeedbackManager(this, mSettingsValues); 48914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); 49017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 49117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 4920ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private void initSuggest() { 493cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); 4943ee7d97587ccbbeb8003d2142478337e8d60b2b7Jean Chalard final Locale keyboardLocale = mSubtypeSwitcher.getInputLocale(); 49536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 49678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka final ContactsDictionary oldContactsDictionary; 49778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka if (mSuggest != null) { 49878ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = mSuggest.getContactsDictionary(); 49978ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.close(); 50078ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } else { 50178ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka oldContactsDictionary = null; 50278ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 503e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 504e6269759d642eac0a03ae6942acb5cd556e7ff46Jean Chalard mSuggest = new Suggest(this, keyboardLocale); 50578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka if (mSettingsValues.mAutoCorrectEnabled) { 50678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); 50778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka } 508e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 50978ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mUserDictionary = new UserDictionary(this, localeStr); 51078ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserDictionary(mUserDictionary); 51178ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); 512e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 51378ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka resetContactsDictionary(oldContactsDictionary); 514e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 51578ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mUserHistoryDictionary = new UserHistoryDictionary( 51678ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka this, localeStr, Suggest.DIC_USER_HISTORY); 51778ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); 518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 51936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 52014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard /** 52114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * Resets the contacts dictionary in mSuggest according to the user settings. 52214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 52314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * This method takes an optional contacts dictionary to use. Since the contacts dictionary 52414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * does not depend on the locale, it can be reused across different instances of Suggest. 52514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * The dictionary will also be opened or closed as necessary depending on the settings. 52614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 52714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * @param oldContactsDictionary an optional dictionary to use, or null 52814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard */ 52914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard private void resetContactsDictionary(final ContactsDictionary oldContactsDictionary) { 53014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard final boolean shouldSetDictionary = (null != mSuggest && mSettingsValues.mUseContactsDict); 53114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 53214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard final ContactsDictionary dictionaryToUse; 53314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (!shouldSetDictionary) { 53414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the dictionary is closed. If it is already closed, this is a no-op, 53514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // so it's safe to call it anyways. 53614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != oldContactsDictionary) oldContactsDictionary.close(); 53714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = null; 53814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else if (null != oldContactsDictionary) { 53914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the old contacts dictionary is opened. If it is already open, this is a 54014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // no-op, so it's safe to call it anyways. 54114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard oldContactsDictionary.reopen(this); 54214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = oldContactsDictionary; 54314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 54414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS); 54514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 54614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 54714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != mSuggest) { 54814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard mSuggest.setContactsDictionary(dictionaryToUse); 54914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 550699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard } 551699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard 552cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /* package private */ void resetSuggestMainDict() { 553e6269759d642eac0a03ae6942acb5cd556e7ff46Jean Chalard mSuggest.resetMainDict(this, mSubtypeSwitcher.getInputLocale()); 554cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard } 555cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 556466741d8a78965b8509bf527344f289e50873092Mike LeBeau @Override 557466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onDestroy() { 558e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa if (mSuggest != null) { 559e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.close(); 560e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest = null; 561979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 562923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project unregisterReceiver(mReceiver); 563cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard unregisterReceiver(mDictionaryPackInstallReceiver); 564979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 565979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.onDestroy(); 566923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onDestroy(); 567923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 568923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 570923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onConfigurationChanged(Configuration conf) { 571dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka mSubtypeSwitcher.onConfigurationChanged(conf); 572b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani // If orientation changed while predicting, commit the change 573f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka if (mDisplayOrientation != conf.orientation) { 574f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = conf.orientation; 575f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mHandler.startOrientationChanging(); 5769351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 57766bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); 578466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (ic != null) ic.finishComposingText(); // For voice input 5792fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka if (isShowingOptionDialog()) 5802fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka mOptionsDialog.dismiss(); 581b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 582923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onConfigurationChanged(conf); 583923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 584b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 586923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public View onCreateInputView() { 5876c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka return mKeyboardSwitcher.onCreateInputView(); 5886c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka } 5896c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka 5906c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka @Override 5916c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka public void setInputView(View view) { 5926c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka super.setInputView(view); 593d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka mExtractArea = getWindow().getWindow().getDecorView() 594d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka .findViewById(android.R.id.extractArea); 595abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); 596913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer = view.findViewById(R.id.suggestions_container); 597913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view); 598913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) 599913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.setListener(this, view); 600f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka if (LatinImeLogger.sVISUALDEBUG) { 601f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); 602f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka } 603923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 604923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 606c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public void setCandidatesView(View view) { 607c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka // To ensure that CandidatesView will never be set. 608c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return; 609923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 611a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker @Override 612e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 613e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInput(editorInfo, restarting); 61459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 61559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 61659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 617e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 618e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInputView(editorInfo, restarting); 61959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 62059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 62159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 62259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 62359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInputView(finishingInput); 62459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 62538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 62659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 62759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 62859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInput(); 62959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 63059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 6319cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka @Override 6329cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) { 6339cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka SubtypeSwitcher.getInstance().updateSubtype(subtype); 6349cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka } 6359cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka 636e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) { 637e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInput(editorInfo, restarting); 63859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 63959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 640e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { 641e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInputView(editorInfo, restarting); 64245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 643c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka LatinKeyboardView inputView = switcher.getKeyboardView(); 6448e09172df1bb176cc899940862c56bed9b9aec4esatok 645ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (editorInfo == null) { 646ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.e(TAG, "Null EditorInfo in onStartInputView()"); 647ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok if (LatinImeLogger.sDBG) { 648ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok throw new NullPointerException("Null EditorInfo in onStartInputView()"); 649ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 650ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok return; 651ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok } 65289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (DEBUG) { 653ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok Log.d(TAG, "onStartInputView: editorInfo:" 654ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok + String.format("inputType=0x%08x imeOptions=0x%08x", 655ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok editorInfo.inputType, editorInfo.imeOptions)); 656910b73127fa207dd26ec8124000262523b0aac0csatok } 6579bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 6589bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onStartInputViewInternal(editorInfo); 6599bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 660cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { 6614f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6624f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6634f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead"); 6644f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 665cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka if (StringUtils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { 6664f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Deprecated private IME option specified: " 6674f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka + editorInfo.privateImeOptions); 6684f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); 6694f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka } 6704f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka 6717ef235f53f2291f22ddf8c56be9860a218b25bbbTadashi G. Takaoka LatinImeLogger.onStartInputView(editorInfo); 672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In landscape mode, this method gets called without the input view being created. 673979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (inputView == null) { 674923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 675923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 677b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette // Forward this event to the accessibility utilities, if enabled. 678b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); 679b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette if (accessUtils.isTouchExplorationEnabled()) { 680e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka accessUtils.onStartInputViewInternal(editorInfo, restarting); 681b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette } 682b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette 6838d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka mSubtypeSwitcher.updateParametersOnStartInputView(); 6844ab730dbd34fad323063f2ffd31ce33de746668dsatok 685b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // The EditorInfo might have a flag that affects fullscreen mode. 686b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // Note: This call should be done by InputMethodService? 687b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka updateFullscreenMode(); 6881fead1d5f12928f90c723b5f7b88490cc7cd2a67Jean Chalard mLastSelectionStart = editorInfo.initialSelStart; 6891fead1d5f12928f90c723b5f7b88490cc7cd2a67Jean Chalard mLastSelectionEnd = editorInfo.initialSelEnd; 69080b66bb166f7f45adfcadcb84788477df9930828Jean Chalard mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode()); 691ccc35f7fa74860a8d737a4e9ff01fc0168dd329dJean Chalard mApplicationSpecifiedCompletions = null; 692c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 693c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.closing(); 694c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mEnteredText = null; 6952692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 696c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mDeleteCount = 0; 697120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 698c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 69917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 70017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard updateCorrectionMode(); 7012ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka updateSuggestionVisibility(mResources); 70217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 70317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) { 70417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); 705549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka } 70617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 707cb389ef0d6e6eec737c249e1729c2a2cdc30f341Tadashi G. Takaoka switcher.loadKeyboard(editorInfo, mSettingsValues); 708c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 709913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) 710913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.clear(); 711913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShownInternal( 712913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka isSuggestionsStripVisible(), /* needsInputViewShown */ false); 713c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka // Delay updating suggestions because keyboard input view may not be shown at this point. 714c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mHandler.postUpdateSuggestions(); 715ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 716c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 717240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn, 718240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard mSettingsValues.mKeyPreviewPopupDismissDelay); 719c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.setProximityCorrectionEnabled(true); 720c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 721c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); 722c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 723c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 725e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka public void onWindowHidden() { 726e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka super.onWindowHidden(); 727f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 728e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka if (inputView != null) inputView.closing(); 729e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 730e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 73159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputInternal() { 732923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onFinishInput(); 733a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 734979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 735979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 736f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 737d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa if (inputView != null) inputView.closing(); 7389ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard if (mUserHistoryDictionary != null) mUserHistoryDictionary.flushPendingWrites(); 739466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 740466741d8a78965b8509bf527344f289e50873092Mike LeBeau 74159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputViewInternal(boolean finishingInput) { 7426495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa super.onFinishInputView(finishingInput); 743055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardSwitcher.onFinishInputView(); 744f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 7455f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (inputView != null) inputView.cancelAllMessages(); 746d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka // Remove pending messages related to update suggestions 747d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.cancelUpdateSuggestions(); 7486495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa } 7496495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa 7506495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa @Override 751923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onUpdateSelection(int oldSelStart, int oldSelEnd, 752923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int newSelStart, int newSelEnd, 753104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard int composingSpanStart, int composingSpanEnd) { 754923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, 755104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard composingSpanStart, composingSpanEnd); 756466741d8a78965b8509bf527344f289e50873092Mike LeBeau 757466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (DEBUG) { 758466741d8a78965b8509bf527344f289e50873092Mike LeBeau Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart 759466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ose=" + oldSelEnd 760025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lss=" + mLastSelectionStart 761025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lse=" + mLastSelectionEnd 762466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nss=" + newSelStart 763466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nse=" + newSelEnd 764104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", cs=" + composingSpanStart 765104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard + ", ce=" + composingSpanEnd); 766466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 7679bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 7689bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onUpdateSelection(mLastSelectionStart, mLastSelectionEnd, 7699bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge oldSelStart, oldSelEnd, newSelStart, newSelEnd, composingSpanStart, 7709bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge composingSpanEnd); 7719bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 772466741d8a78965b8509bf527344f289e50873092Mike LeBeau 773104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // TODO: refactor the following code to be less contrived. 774104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "newSelStart != composingSpanEnd" || "newSelEnd != composingSpanEnd" means 775104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // that the cursor is not at the end of the composing span, or there is a selection. 776104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // "mLastSelectionStart != newSelStart" means that the cursor is not in the same place 777104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // as last time we were called (if there is a selection, it means the start hasn't 778104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // changed, so it's the end that did). 779104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean selectionChanged = (newSelStart != composingSpanEnd 780104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard || newSelEnd != composingSpanEnd) && mLastSelectionStart != newSelStart; 781104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // if composingSpanStart and composingSpanEnd are -1, it means there is no composing 782104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // span in the view - we can use that to narrow down whether the cursor was moved 783104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // by us or not. If we are composing a word but there is no composing span, then 784104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // we know for sure the cursor moved while we were composing and we should reset 785104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // the state. 786104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard final boolean noComposingSpan = composingSpanStart == -1 && composingSpanEnd == -1; 7874733609947c0ec74e460bd714fffca0518ade93aJean Chalard if (!mExpectingUpdateSelection) { 788cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // TAKE CARE: there is a race condition when we enter this test even when the user 789cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // did not explicitly move the cursor. This happens when typing fast, where two keys 790cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // turn this flag on in succession and both onUpdateSelection() calls arrive after 791cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // the second one - the first call successfully avoids this test, but the second one 792104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard // enters. For the moment we rely on noComposingSpan to further reduce the impact. 79351fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 7949a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // TODO: the following is probably better done in resetEntireInputState(). 7959a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // it should only happen when the cursor moved, and the very purpose of the 7969a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // test below is to narrow down whether this happened or not. Likewise with 7979a2a11e65bd32d82754b3fcff74e9e3795327628Jean Chalard // the call to postUpdateShiftState. 79851fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // We set this to NONE because after a cursor move, we don't want the space 79951fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // state-related special processing to kick in. 80051fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard mSpaceState = SPACE_STATE_NONE; 80151fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard 8028a3d369840d6061692a19ceb1eb7267a50a9e056Jean Chalard if ((!mWordComposer.isComposingWord()) || selectionChanged || noComposingSpan) { 8032649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetEntireInputState(); 8044c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 805beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka 806beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 8074733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 8084733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = false; 8096b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not 8106b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // here. It would probably be too expensive to call directly here but we may want to post a 8116b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // message to delay it. The point would be to unify behavior between backspace to the 8126b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // end of a word and manually put the pointer at the end of the word. 813466741d8a78965b8509bf527344f289e50873092Mike LeBeau 814979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Make a note of the cursor position 815979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionStart = newSelStart; 816979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionEnd = newSelEnd; 8177a8dac55278cedd838be325f56b4c52d973c61f5satok } 8187a8dac55278cedd838be325f56b4c52d973c61f5satok 819c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 820c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has clicked on the extracted text view, 821c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * when running in fullscreen mode. The default implementation hides 822913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * the suggestions view when this happens, but only if the extracted text 823c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * editor has a vertical scroll bar because its text doesn't fit. 824c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 825913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 826c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 827c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 828c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedTextClicked() { 829fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard if (isSuggestionsRequested()) return; 830c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 831c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedTextClicked(); 832c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 833c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 834c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 835c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has performed a cursor movement in the 836c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * extracted text view, when it is running in fullscreen mode. The default 837913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * implementation hides the suggestions view when a vertical movement 838c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * happens, but only if the extracted text editor has a vertical scroll bar 839c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * because its text doesn't fit. 840c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 841913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 842c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 843c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 844c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedCursorMovement(int dx, int dy) { 845fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard if (isSuggestionsRequested()) return; 846c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 847c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedCursorMovement(dx, dy); 848c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 849c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void hideWindow() { 852979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 853c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mKeyboardSwitcher.onHideWindow(); 854979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (TRACE) Debug.stopMethodTracing(); 8566e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani if (mOptionsDialog != null && mOptionsDialog.isShowing()) { 8576e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog.dismiss(); 8586e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog = null; 8596e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.hideWindow(); 861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 8641b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) { 865979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG) { 866a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa Log.i(TAG, "Received completions:"); 867bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok if (applicationSpecifiedCompletions != null) { 868bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 869bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); 870bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok } 871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 872923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 8739bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 8749bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions); 8759bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 876dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn) { 8771b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; 8781b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka if (applicationSpecifiedCompletions == null) { 879b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani clearSuggestions(); 880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 881923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 882a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 883660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords = 88488bf1ba5263f5a5c1df367ddc401db4109ef8677Jean Chalard SuggestedWords.getFromApplicationSpecifiedCompletions( 8851dfef0336d5968dbd00b73489778cee1fb233d56Jean Chalard applicationSpecifiedCompletions); 886bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard final SuggestedWords suggestedWords = new SuggestedWords( 8877d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard applicationSuggestedWords, 8882e2519ee914d4bf9462950553840557a4c19faedJean Chalard false /* typedWordValid */, 889bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard false /* hasAutoCorrectionCandidate */, 890b5eeb724fc98bb7169683539027d9ba54ffb8b14Jean Chalard false /* allowsToBeAutoCorrected */, 89103a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isPunctuationSuggestions */, 89203a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isObsoleteSuggestions */); 893979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // When in fullscreen mode, show completions generated by the application 8944e112d07821d34c1dedd21b086817be9fce2fd47Jean Chalard final boolean isAutoCorrection = false; 8957d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard setSuggestions(suggestedWords, isAutoCorrection); 896dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 897b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard // TODO: is this the right thing to do? What should we auto-correct to in 898b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard // this case? This says to keep whatever the user typed. 899b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 900c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShown(true); 901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 904c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { 905913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // TODO: Modify this if we support suggestions with hard keyboard 906913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { 907433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 908433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final boolean inputViewShown = (keyboardView != null) ? keyboardView.isShown() : false; 909913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean shouldShowSuggestions = shown 910433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka && (needsInputViewShown ? inputViewShown : true); 9114b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka if (isFullscreenMode()) { 912913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 913913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.GONE); 9147a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } else { 915913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 916913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); 9177a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } 918923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 919923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 920a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 921c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShown(boolean shown) { 922c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); 923543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa } 924543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa 925c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka private void adjustInputViewHeight() { 926c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka if (mKeyPreviewBackingView.getHeight() > 0) { 927c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return; 928c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 929c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 930c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final KeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 931c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka if (keyboardView == null) return; 932c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int keyboardHeight = keyboardView.getHeight(); 933c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int suggestionsHeight = mSuggestionsContainer.getHeight(); 934c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int displayHeight = mResources.getDisplayMetrics().heightPixels; 935c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final Rect rect = new Rect(); 936c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect); 937c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int notificationBarHeight = rect.top; 938c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight 939c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka - keyboardHeight; 940c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 941c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final LayoutParams params = mKeyPreviewBackingView.getLayoutParams(); 942c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka params.height = mSuggestionsView.setMoreSuggestionsHeight(remainingHeight); 943c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mKeyPreviewBackingView.setLayoutParams(params); 944c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 945c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 946543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa @Override 947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onComputeInsets(InputMethodService.Insets outInsets) { 948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onComputeInsets(outInsets); 949f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 950913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (inputView == null || mSuggestionsContainer == null) 95146ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka return; 952c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka adjustInputViewHeight(); 953d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // In fullscreen mode, the height of the extract area managed by InputMethodService should 954d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // be considered. 955d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. 956d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0; 957abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka final int backingHeight = (mKeyPreviewBackingView.getVisibility() == View.GONE) ? 0 958abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka : mKeyPreviewBackingView.getHeight(); 95959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0 96059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka : mSuggestionsContainer.getHeight(); 961d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extraHeight = extractHeight + backingHeight + suggestionsHeight; 962abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka int touchY = extraHeight; 9639e347d3d448e48229c46aad394ec9bd60cd5807bsatok // Need to set touchable region only if input view is being shown 964433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 965433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka if (keyboardView != null && keyboardView.isShown()) { 966913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { 96759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka touchY -= suggestionsHeight; 9689e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 9697a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka final int touchWidth = inputView.getWidth(); 970abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka final int touchHeight = inputView.getHeight() + extraHeight 9717a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka // Extend touchable region below the keyboard. 9727a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + EXTENDED_TOUCHABLE_REGION_HEIGHT; 97313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; 97413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight); 9759e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 97646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.contentTopInsets = touchY; 97746ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.visibleTopInsets = touchY; 978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 979a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 981979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean onEvaluateFullscreenMode() { 9829751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka // Reread resource value here, because this method is called by framework anytime as needed. 9839751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka final boolean isFullscreenModeAllowed = 9849751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka mSettingsValues.isFullscreenModeAllowed(getResources()); 9859751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka return super.onEvaluateFullscreenMode() && isFullscreenModeAllowed; 98659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka } 98759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka 98859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka @Override 98959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka public void updateFullscreenMode() { 99059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka super.updateFullscreenMode(); 991f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka 99259010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka if (mKeyPreviewBackingView == null) return; 993549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka // In fullscreen mode, no need to have extra space to show the key preview. 99459010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka // If not, we should have extra space above the keyboard to show the key preview. 995549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); 996979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 997979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 998979f8690967ff5409fe18f5085858ccdb8e0ccf1satok @Override 999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) { 1000923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (keyCode) { 1001e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_BACK: 10022cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka if (event.getRepeatCount() == 0) { 10032cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka if (mSuggestionsView != null && mSuggestionsView.handleBack()) { 10042cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka return true; 10052cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka } 10062cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 10072cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka if (keyboardView != null && keyboardView.handleBack()) { 10086e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani return true; 10096e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 1010e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 1011e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka break; 1012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return super.onKeyDown(keyCode, event); 1014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 1017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean onKeyUp(int keyCode, KeyEvent event) { 1018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (keyCode) { 1019e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_DOWN: 1020e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_UP: 1021e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_LEFT: 1022e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_RIGHT: 1023433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 1024433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 1025e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka // Enable shift key and DPAD to do selections 1026433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka if ((keyboardView != null && keyboardView.isShown()) 1027433ca6a46db30a321715da0f457974916668dff5Tadashi G. Takaoka && (keyboard != null && keyboard.isShiftedOrShiftLocked())) { 1028e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(), 1029e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka event.getAction(), event.getKeyCode(), event.getRepeatCount(), 1030e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka event.getDeviceId(), event.getScanCode(), 1031e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON); 10329351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1033e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka if (ic != null) 1034e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ic.sendKeyEvent(newEvent); 1035e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka return true; 1036e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 1037e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka break; 1038923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1039923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return super.onKeyUp(keyCode, event); 1040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 10422649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // This will reset the whole input state to the starting state. It will clear 10432649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // the composing word, reset the last composed word, tell the inputconnection 10442649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard // and the composingStateManager about it. 10452649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard private void resetEntireInputState() { 10462649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 10472649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard updateSuggestions(); 10482649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard final InputConnection ic = getCurrentInputConnection(); 10492649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard if (ic != null) { 10502649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard ic.finishComposingText(); 10512649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard } 10522649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard } 10532649e42d756132ad763d6db5f9de1f901bbefd06Jean Chalard 10542692a8700737d8eed268039aa27b22a31669da08Jean Chalard private void resetComposingState(final boolean alsoResetLastComposedWord) { 10552692a8700737d8eed268039aa27b22a31669da08Jean Chalard mWordComposer.reset(); 10562692a8700737d8eed268039aa27b22a31669da08Jean Chalard if (alsoResetLastComposedWord) 10572692a8700737d8eed268039aa27b22a31669da08Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 10582692a8700737d8eed268039aa27b22a31669da08Jean Chalard } 10592692a8700737d8eed268039aa27b22a31669da08Jean Chalard 106066bb563535dbe3672f99f75bd71763a551444867Jean Chalard public void commitTyped(final InputConnection ic, final int separatorCode) { 1061196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) return; 10623651220327c051d8017045aa5e8919461507b3f8Jean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 10633651220327c051d8017045aa5e8919461507b3f8Jean Chalard if (typedWord.length() > 0) { 1064cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard mLastComposedWord = mWordComposer.commitWord( 106566bb563535dbe3672f99f75bd71763a551444867Jean Chalard LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD, typedWord.toString(), 106666bb563535dbe3672f99f75bd71763a551444867Jean Chalard separatorCode); 10679351550dc6af7859e5280e16144c9386a37b976dKen Wakasa if (ic != null) { 10683651220327c051d8017045aa5e8919461507b3f8Jean Chalard ic.commitText(typedWord, 1); 1069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1070c24f66e18007b5aba32bfab8f86eb7f03fa6c1b7Jean Chalard addToUserHistoryDictionary(typedWord); 1071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 10728558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa updateSuggestions(); 1073923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1074923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1075b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public boolean getCurrentAutoCapsState() { 10769351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 10771c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani EditorInfo ei = getCurrentInputEditorInfo(); 107817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSettingsValues.mAutoCap && ic != null && ei != null 107917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard && ei.inputType != InputType.TYPE_NULL) { 1080b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return ic.getCursorCapsMode(ei.inputType) != 0; 10811c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 1082b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 10831c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 10841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1085b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard // "ic" may be null 1086b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard private void swapSwapperAndSpaceWhileInBatchEdit(final InputConnection ic) { 1087b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard if (null == ic) return; 1088923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project CharSequence lastTwo = ic.getTextBeforeCursor(2, 0); 1089863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. 1090923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastTwo != null && lastTwo.length() == 2 1091863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard && lastTwo.charAt(0) == Keyboard.CODE_SPACE) { 1092923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.deleteSurroundingText(2, 0); 1093923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.commitText(lastTwo.charAt(1) + " ", 1); 1094b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 10954ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 10964ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 10974ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1098120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private boolean maybeDoubleSpaceWhileInBatchEdit(final InputConnection ic) { 1099120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (mCorrectionMode == Suggest.CORRECTION_NONE) return false; 1100120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (ic == null) return false; 11012b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); 1102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastThree != null && lastThree.length() == 3 1103cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka && StringUtils.canBeFollowedByPeriod(lastThree.charAt(0)) 1104571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastThree.charAt(1) == Keyboard.CODE_SPACE 1105fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka && lastThree.charAt(2) == Keyboard.CODE_SPACE 1106fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka && mHandler.isAcceptingDoubleSpaces()) { 1107fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka mHandler.cancelDoubleSpacesTimer(); 1108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.deleteSurroundingText(2, 0); 1109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.commitText(". ", 1); 1110b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1111120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 1112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1113120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return false; 1114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1115a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1116b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard // "ic" may be null 11178fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { 11189a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic == null) return; 1119b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); 11209a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (lastOne != null && lastOne.length() == 1 1121571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastOne.charAt(0) == Keyboard.CODE_SPACE) { 11229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa ic.deleteSurroundingText(1, 0); 11239a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 11249a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 11259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa 1126c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 1127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean addWordToDictionary(String word) { 1128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mUserDictionary.addWord(word, 128); 11296558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // Suggestion strip should be updated after the operation of adding word to the 11306558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // user dictionary 1131d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 11358fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean isAlphabet(int code) { 11368fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka return Character.isLetter(code); 1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1138a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1139e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka private void onSettingsKeyPressed() { 1140cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return; 1141911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa showSubtypeSelectorAndSettings(); 11429a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11439a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1144cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa // Virtual codes representing custom requests. These are used in onCustomRequest() below. 1145cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; 1146d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka public static final int CODE_HAPTIC_AND_AUDIO_FEEDBACK = 2; 1147cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa 1148cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa @Override 1149cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public boolean onCustomRequest(int requestCode) { 1150cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return false; 1151cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa switch (requestCode) { 1152cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa case CODE_SHOW_INPUT_METHOD_PICKER: 1153cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { 115479efbed76f638be298493107fa2d0cd1b5eb529esatok mImm.showInputMethodPicker(); 1155cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return true; 11569a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1157cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 1158d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka case CODE_HAPTIC_AND_AUDIO_FEEDBACK: 1159d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka hapticAndAudioFeedback(Keyboard.CODE_UNSPECIFIED); 1160d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka return true; 11619a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1162cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 11639a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11649a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 11659a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok private boolean isShowingOptionDialog() { 11669a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok return mOptionsDialog != null && mOptionsDialog.isShowing(); 11679a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11689a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 116905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka private static int getActionId(Keyboard keyboard) { 117005bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka return keyboard != null ? keyboard.mId.imeActionId() : EditorInfo.IME_ACTION_NONE; 11717a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11727a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 11738f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka private void performEditorAction(int actionId) { 11747a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 11757a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (ic != null) { 11767a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka ic.performEditorAction(actionId); 11777a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11787a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 11797a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 118081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka private void handleLanguageSwitchKey() { 1181c1ca8815f59bb1bce25e521571a1d87c71bf3fc3Ken Wakasa final boolean includesOtherImes = mSettingsValues.mIncludesOtherImesInLanguageSwitchList; 118281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka final IBinder token = getWindow().getWindow().getAttributes().token; 118381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if (mShouldSwitchToLastSubtype) { 11849cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka final InputMethodSubtype lastSubtype = mImm.getLastInputMethodSubtype(); 1185cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka final boolean lastSubtypeBelongsToThisIme = SubtypeUtils.checkIfSubtypeBelongsToThisIme( 118681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka this, lastSubtype); 118781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka if ((includesOtherImes || lastSubtypeBelongsToThisIme) 118881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka && mImm.switchToLastInputMethod(token)) { 118981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = false; 119081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else { 119181d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mImm.switchToNextInputMethod(token, !includesOtherImes); 119281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 119381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 119481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } else { 119581d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mImm.switchToNextInputMethod(token, !includesOtherImes); 119681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 119781d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka } 119881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka 11997a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka private void sendKeyCodePoint(int code) { 12007a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // TODO: Remove this special handling of digit letters. 12017a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. 12027a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (code >= '0' && code <= '9') { 12037a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka super.sendKeyChar((char)code); 12047a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka return; 12057a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12067a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 12077a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 12087a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka if (ic != null) { 12097a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka final String text = new String(new int[] { code }, 0, 1); 12107a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka ic.commitText(text, text.length()); 12117a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12127a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka } 12137a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka 12145f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Implementation of {@link KeyboardActionListener}. 12155a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 1216ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok public void onCodeInput(int primaryCode, int x, int y) { 1217175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final long when = SystemClock.uptimeMillis(); 1218571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { 1219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDeleteCount = 0; 1220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mLastKeyTime = when; 1222fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge 1223c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ProductionFlag.IS_EXPERIMENTAL) { 1224c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa if (ResearchLogger.sIsLogging) { 1225c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa ResearchLogger.getInstance().logKeyEvent(primaryCode, x, y); 1226c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa } 1227fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge } 1228fdd68f06579ab338f5d33115aa8300431c75b4faKurt Partridge 1229175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1230120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // The space state depends only on the last character pressed and its own previous 1231120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // state. Here, we revert the space state to neutral if the key is actually modifying 1232120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // the input contents (any non-shift key), which is what we should do for 1233120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // all inputs that do not result in a special state. Each character handling is then 1234120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // free to override the state as they see fit. 1235120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState = mSpaceState; 123670852c91dc7209d0aaa875a2cb0f79739c7398e6Jean Chalard if (!mWordComposer.isComposingWord()) mIsAutoCorrectionIndicatorOn = false; 1237ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1238ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa // TODO: Consolidate the double space timer, mLastKeyTime, and the space state. 1239ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa if (primaryCode != Keyboard.CODE_SPACE) { 1240ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 1241ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa } 1242ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1243c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 1245571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_DELETE: 1246120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1247120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleBackspace(spaceState); 12484189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka mDeleteCount++; 12494733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 125081d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 1251140467b8b65eb9087a9b7f744dbb8a30481effe7Kurt Partridge LatinImeLogger.logOnDelete(x, y); 12524189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1253571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_SHIFT: 1254e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 12552a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka // Shift and symbol key is handled in onPressKey() and onReleaseKey(). 12564189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1257e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SETTINGS: 125893246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka onSettingsKeyPressed(); 12594189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1260d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka case Keyboard.CODE_SHORTCUT: 126193246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka mSubtypeSwitcher.switchToShortcutIME(); 12624189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 12637a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka case Keyboard.CODE_ACTION_ENTER: 12648f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(getActionId(switcher.getKeyboard())); 12657a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka break; 126605bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case Keyboard.CODE_ACTION_NEXT: 12678f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_NEXT); 126805bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka break; 126905bfd189a88be79ddfc74d0ea21792e2fb78f2aaTadashi G. Takaoka case Keyboard.CODE_ACTION_PREVIOUS: 12708f433a66b2e8b327d7854eb501cf0e93afed4117Tadashi G. Takaoka performEditorAction(EditorInfo.IME_ACTION_PREVIOUS); 12714189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 127281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka case Keyboard.CODE_LANGUAGE_SWITCH: 127381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka handleLanguageSwitchKey(); 127481d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka break; 12754189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka default: 1276120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 127717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSettingsValues.isWordSeparator(primaryCode)) { 1278c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); 12794189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 12808dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 12818dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { 12828dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka handleCharacter(primaryCode, x, y, spaceState); 12838dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } else { 12848dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka handleCharacter(primaryCode, NOT_A_TOUCH_COORDINATE, NOT_A_TOUCH_COORDINATE, 12858dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka spaceState); 12868dcad2ed4776b849ddacb623a94b4301afcf055aTadashi G. Takaoka } 12874189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 12884733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 128981d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka mShouldSwitchToLastSubtype = true; 12904733609947c0ec74e460bd714fffca0518ade93aJean Chalard break; 1291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1292eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka switcher.onCodeInput(primaryCode); 1293dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Reset after any single keystroke 1294c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard if (!didAutoCorrect) 1295c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard mLastComposedWord.deactivate(); 1296dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = null; 1297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1298a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 12995a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13008aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onTextInput(CharSequence text) { 13019351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic == null) return; 1303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.beginBatchEdit(); 130466bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitTyped(ic, LastComposedWord.NOT_A_SEPARATOR); 1305fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard text = specificTldProcessingOnTextInput(ic, text); 1306fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == mSpaceState) { 13077a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 1308fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.commitText(text, 1); 1310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.endBatchEdit(); 1311b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 13128cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); 1313120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1314dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = text; 13152692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 1316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1317923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1318fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // ic may not be null 1319fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard private CharSequence specificTldProcessingOnTextInput(final InputConnection ic, 1320fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard final CharSequence text) { 1321fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (text.length() <= 1 || text.charAt(0) != Keyboard.CODE_PERIOD 1322fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard || !Character.isLetter(text.charAt(1))) { 1323fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Not a tld: do nothing. 1324fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1325fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 132612d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // We have a TLD (or something that looks like this): make sure we don't add 132712d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard // a space even if currently in phantom mode. 132812d67e6d5d5bd764117038f3f666d4d7da0c10eaJean Chalard mSpaceState = SPACE_STATE_NONE; 1329fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); 1330fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (lastOne != null && lastOne.length() == 1 1331fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard && lastOne.charAt(0) == Keyboard.CODE_PERIOD) { 1332fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text.subSequence(1, text.length()); 1333fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else { 1334fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard return text; 1335fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1336fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1337fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 13385a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13398aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() { 134083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka // User released a finger outside any key 13415f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka mKeyboardSwitcher.onCancelInput(); 134283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } 134383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka 1344120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleBackspace(final int spaceState) { 1345504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 1346504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka if (ic == null) return; 1347979f8690967ff5409fe18f5085858ccdb8e0ccf1satok ic.beginBatchEdit(); 1348a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard handleBackspaceWhileInBatchEdit(spaceState, ic); 1349a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard ic.endBatchEdit(); 1350a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard } 1351979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1352a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard // "ic" may not be null. 1353a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) { 13542245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard // In many cases, we may have to put the keyboard in auto-shift state again. 1355beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka mHandler.postUpdateShiftState(); 13562245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard 13575c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { 13585c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // Cancel multi-character input: remove the text we just entered. 13595c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // This is triggered on backspace after a key that inputs multiple characters, 13605c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // like the smiley key or the .com key. 13615c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard ic.deleteSurroundingText(mEnteredText.length(), 0); 13625c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. 13635c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // In addition we know that spaceState is false, and that we should not be 13645c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // reverting any autocorrect at this point. So we can safely return. 13655c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard return; 13665c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard } 13675c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard 1368196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 13693651220327c051d8017045aa5e8919461507b3f8Jean Chalard final int length = mWordComposer.size(); 1370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (length > 0) { 13719318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.deleteLast(); 137277d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1373196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // If we have deleted the last remaining character of a word, then we are not 1374196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // isComposingWord() any more. 1375196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) { 1376196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // Not composing word any more, so we can show bigrams. 1377cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.postUpdateBigramPredictions(); 137889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1379196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // Still composing a word, so we still have letters to deduce a suggestion from. 138089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard mHandler.postUpdateSuggestions(); 138189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 1382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1383923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.deleteSurroundingText(1, 0); 1384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1385890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } else { 13865935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard if (mLastComposedWord.canRevertCommit()) { 1387d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard Utils.Stats.onAutoCorrectionCancellation(); 13885935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard revertCommit(ic); 1389120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return; 1390120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1391d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (SPACE_STATE_DOUBLE == spaceState) { 13922124bc5bf5af31cf3d2789b70ebd2f24c815f5f4Jean Chalard if (revertDoubleSpaceWhileInBatchEdit(ic)) { 1393d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // No need to reset mSpaceState, it has already be done (that's why we 1394d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // receive it as a parameter) 1395d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1396d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 1397d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1398d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (revertSwapPunctuation(ic)) { 1399d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // Likewise 1400d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1401d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 14024733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 1403504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka 14044fef31510df542a3324426a6750950194d016086Jean Chalard // No cancelling of commit/double space/swap: we have a regular backspace. 14054fef31510df542a3324426a6750950194d016086Jean Chalard // We should backspace one char and restart suggestion if at the end of a word. 14064fef31510df542a3324426a6750950194d016086Jean Chalard if (mLastSelectionStart != mLastSelectionEnd) { 14074fef31510df542a3324426a6750950194d016086Jean Chalard // If there is a selection, remove it. 14084fef31510df542a3324426a6750950194d016086Jean Chalard final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart; 14094fef31510df542a3324426a6750950194d016086Jean Chalard ic.setSelection(mLastSelectionEnd, mLastSelectionEnd); 14104fef31510df542a3324426a6750950194d016086Jean Chalard ic.deleteSurroundingText(lengthToDelete, 0); 14116558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } else { 14124fef31510df542a3324426a6750950194d016086Jean Chalard // There is no selection, just delete one character. 14134fef31510df542a3324426a6750950194d016086Jean Chalard if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) { 14144fef31510df542a3324426a6750950194d016086Jean Chalard // This should never happen. 14154fef31510df542a3324426a6750950194d016086Jean Chalard Log.e(TAG, "Backspace when we don't know the selection position"); 14166558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 14174fef31510df542a3324426a6750950194d016086Jean Chalard ic.deleteSurroundingText(1, 0); 14184fef31510df542a3324426a6750950194d016086Jean Chalard if (mDeleteCount > DELETE_ACCELERATE_AT) { 14194fef31510df542a3324426a6750950194d016086Jean Chalard ic.deleteSurroundingText(1, 0); 1420edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 14224fef31510df542a3324426a6750950194d016086Jean Chalard if (isSuggestionsRequested()) { 14234fef31510df542a3324426a6750950194d016086Jean Chalard restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); 14244fef31510df542a3324426a6750950194d016086Jean Chalard } 1425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1426923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1427923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1428e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard // ic may be null 1429e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard private boolean maybeStripSpaceWhileInBatchEdit(final InputConnection ic, final int code, 1430e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final int spaceState, final boolean isFromSuggestionStrip) { 1431e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1432e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard removeTrailingSpaceWhileInBatchEdit(ic); 1433e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1434e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else if ((SPACE_STATE_WEAK == spaceState 1435e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard || SPACE_STATE_SWAP_PUNCTUATION == spaceState) 1436e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard && isFromSuggestionStrip) { 1437b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard if (mSettingsValues.isWeakSpaceSwapper(code)) { 1438e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return true; 1439e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1440b141c9cd3f6785bc0a4e1f5385f4e6e2e17955bbJean Chalard if (mSettingsValues.isWeakSpaceStripper(code)) { 1441e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard removeTrailingSpaceWhileInBatchEdit(ic); 1442e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1443e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1444e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1445e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } else { 1446e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard return false; 1447e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1448e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1449e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1450ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void handleCharacter(final int primaryCode, final int x, 1451120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int y, final int spaceState) { 1452b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard final InputConnection ic = getCurrentInputConnection(); 1453dafa7a8e15447544842975047f831883e67700c5Jean Chalard if (null != ic) ic.beginBatchEdit(); 1454dafa7a8e15447544842975047f831883e67700c5Jean Chalard // TODO: if ic is null, does it make any sense to call this? 1455ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok handleCharacterWhileInBatchEdit(primaryCode, x, y, spaceState, ic); 1456dafa7a8e15447544842975047f831883e67700c5Jean Chalard if (null != ic) ic.endBatchEdit(); 1457dafa7a8e15447544842975047f831883e67700c5Jean Chalard } 1458dafa7a8e15447544842975047f831883e67700c5Jean Chalard 1459dafa7a8e15447544842975047f831883e67700c5Jean Chalard // "ic" may be null without this crashing, but the behavior will be really strange 1460ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok private void handleCharacterWhileInBatchEdit(final int primaryCode, 1461dafa7a8e15447544842975047f831883e67700c5Jean Chalard final int x, final int y, final int spaceState, final InputConnection ic) { 1462196d82cdd740580ed79d801483dbc282be85d076Jean Chalard boolean isComposingWord = mWordComposer.isComposingWord(); 1463fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1464fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (SPACE_STATE_PHANTOM == spaceState && 1465fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard !mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) { 1466fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (isComposingWord) { 1467fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // Sanity check 1468fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard throw new RuntimeException("Should not be composing here"); 1469fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 14707a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(Keyboard.CODE_SPACE); 1471fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } 1472fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard 1473e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if ((isAlphabet(primaryCode) 1474e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) 14753889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa && isSuggestionsRequested() && !isCursorTouchingWord()) { 14767b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (!isComposingWord) { 14776d1cbbc2ffb9d7046189174ec68b5b72bbc154b3Jean Chalard // Reset entirely the composing state anyway, then start composing a new word unless 14787b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard // the character is a single quote. The idea here is, single quote is not a 14797b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard // separator and it should be treated as a normal character, except in the first 14807b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard // position where it should not start composing a word. 1481e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode); 14822692a8700737d8eed268039aa27b22a31669da08Jean Chalard // Here we don't need to reset the last composed word. It will be reset 14832692a8700737d8eed268039aa27b22a31669da08Jean Chalard // when we commit this one, if we ever do; if on the other hand we backspace 14842692a8700737d8eed268039aa27b22a31669da08Jean Chalard // it entirely and resume suggestions on the previous word, we'd like to still 14852692a8700737d8eed268039aa27b22a31669da08Jean Chalard // have touch coordinates for it. 14862692a8700737d8eed268039aa27b22a31669da08Jean Chalard resetComposingState(false /* alsoResetLastComposedWord */); 1487611a5bdf650f7bc54bf40176f84f1cd9c87aa9aaJean Chalard clearSuggestions(); 1488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 14907b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (isComposingWord) { 1491ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok mWordComposer.add( 1492ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok primaryCode, x, y, mKeyboardSwitcher.getKeyboardView().getKeyDetector()); 1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 14941c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani // If it's the first letter, make note of auto-caps state 14959318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa if (mWordComposer.size() == 1) { 14969318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.setAutoCapitalized(getCurrentAutoCapsState()); 14971c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 149877d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1500d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1502e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, 1503e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); 1504863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 15057a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 1506e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard 1507e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (swapWeakSpace) { 1508e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard swapSwapperAndSpaceWhileInBatchEdit(ic); 1509e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard mSpaceState = SPACE_STATE_WEAK; 1510e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 15115262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // Some characters are not word separators, yet they don't start a new 15125262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // composing span. For these, we haven't changed the suggestion strip, and 15135262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // if the "add to dictionary" hint is shown, we should do so now. Examples of 15145262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // such characters include single quote, dollar, and others; the exact list is 15155262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // the list of characters for which we enter handleCharacterWhileInBatchEdit 15165262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard // that don't match the test if ((isAlphabet...)) at the top of this method. 15175262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard if (null != mSuggestionsView && mSuggestionsView.dismissAddToDictionaryHint()) { 15185262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard mHandler.postUpdateBigramPredictions(); 15195262fe8832e69b5d4b2c575524da3757435644f0Jean Chalard } 1520e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard } 1521e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard Utils.Stats.onNonSeparator((char)primaryCode, x, y); 1522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1524c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard // Returns true if we did an autocorrection, false otherwise. 1525c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard private boolean handleSeparator(final int primaryCode, final int x, final int y, 1526120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState) { 152755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa // Should dismiss the "Touch again to save" message when handling separator 1528913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { 1529cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.cancelUpdateBigramPredictions(); 1530d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 15316558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 15326558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 1533c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard boolean didAutoCorrect = false; 1534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Handle separator 15351b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 1536923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 1537923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.beginBatchEdit(); 1538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1539196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 1540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In certain languages where single quote is a separator, it's better 1541a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker // not to auto correct, but accept the typed word. For instance, 1542923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // in Italian dov' should not be expanded to dove' because the elision 1543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // requires the last vowel to be removed. 1544f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled 1545dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && !mInputAttributes.mInputTypeNoAutoCorrect; 154617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { 1547f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard commitCurrentAutoCorrection(primaryCode, ic); 1548c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard didAutoCorrect = true; 1549923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 155066bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitTyped(ic, primaryCode); 1551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15534ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1554e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, spaceState, 1555e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x); 1556863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 155700ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard if (SPACE_STATE_PHANTOM == spaceState && 155800ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard mSettingsValues.isPhantomSpacePromotingSymbol(primaryCode)) { 155900ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard sendKeyCodePoint(Keyboard.CODE_SPACE); 156000ed3be95cee472685bcba1ea861ac75c61db690Jean Chalard } 15617a39bd4454664b5c37b30e9b5362ddbcdce3b374Tadashi G. Takaoka sendKeyCodePoint(primaryCode); 156289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 156389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (Keyboard.CODE_SPACE == primaryCode) { 1564120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (isSuggestionsRequested()) { 1565120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (maybeDoubleSpaceWhileInBatchEdit(ic)) { 1566120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_DOUBLE; 1567120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else if (!isShowingPunctuationList()) { 1568120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_WEAK; 1569120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1570126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 1571120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1572120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mHandler.startDoubleSpacesTimer(); 157389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (!isCursorTouchingWord()) { 157489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard mHandler.cancelUpdateSuggestions(); 1575cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.postUpdateBigramPredictions(); 157689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 157789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1578fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard if (swapWeakSpace) { 1579120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard swapSwapperAndSpaceWhileInBatchEdit(ic); 15804721427c7de3600f6fe7dfff16508a6a974fb3e4Jean Chalard mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; 1581fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard } else if (SPACE_STATE_PHANTOM == spaceState) { 1582fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // If we are in phantom space state, and the user presses a separator, we want to 1583fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // stay in phantom space state so that the next keypress has a chance to add the 1584fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // space. For example, if I type "Good dat", pick "day" from the suggestion strip 1585fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // then insert a comma and go on to typing the next word, I want the space to be 1586fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // inserted automatically before the next word, the same way it is when I don't 1587fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // input the comma. 1588fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1589120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1590120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 159189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Set punctuation right away. onUpdateSelection will fire but tests whether it is 159289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // already displayed or not, so it's okay. 159355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka setPunctuationSuggestions(); 1594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1595120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1596406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)primaryCode, x, y); 1597120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 1599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.endBatchEdit(); 1600923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1601c7c152de4b42853086fc6fd918387ad0583d0e3eJean Chalard return didAutoCorrect; 1602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1603466741d8a78965b8509bf527344f289e50873092Mike LeBeau 160477d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard private CharSequence getTextWithUnderline(final CharSequence text) { 16050a59ac2ba88ac1f99151d9336136bc6fe7d416c0Jean Chalard return mIsAutoCorrectionIndicatorOn 160677d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) 1607fda847a870829f1491cbd5325f9c985213081149Jean Chalard : text; 160877d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 160977d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard 1610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void handleClose() { 161166bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitTyped(getCurrentInputConnection(), LastComposedWord.NOT_A_SEPARATOR); 1612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestHideSelf(0); 1613c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 16141679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka if (inputView != null) 16151679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka inputView.closing(); 1616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 16187a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isSuggestionsRequested() { 1619dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard return mInputAttributes.mIsSettingsSuggestionStripOn 1620c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka && (mCorrectionMode > 0 || isShowingSuggestionsStrip()); 1621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1622a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 16237a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isShowingPunctuationList() { 1624cb8cb95d0afd340de9f1a0e15948f0068d2450bcKen Wakasa if (mSuggestionsView == null) return false; 1625913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mSettingsValues.mSuggestPuncList == mSuggestionsView.getSuggestions(); 16267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 16287a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isShowingSuggestionsStrip() { 16297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE) 16307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE 163138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT); 16327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1634913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public boolean isSuggestionsStripVisible() { 1635913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView == null) 1636b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa return false; 1637d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard if (mSuggestionsView.isShowingAddToDictionaryHint()) 16389fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16399fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (!isShowingSuggestionsStrip()) 16409fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return false; 1641dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn) 16429fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16439fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return isSuggestionsRequested(); 1644923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1646409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void switchToKeyboardView() { 1647060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (DEBUG) { 1648060efb6d82af1f896d90cb845c8ae07c726f85e1satok Log.d(TAG, "Switch to keyboard view."); 1649060efb6d82af1f896d90cb845c8ae07c726f85e1satok } 16509bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 16519bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge ResearchLogger.latinIME_switchToKeyboardView(); 16529bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge } 1653c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka View v = mKeyboardSwitcher.getKeyboardView(); 1654060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (v != null) { 1655060efb6d82af1f896d90cb845c8ae07c726f85e1satok // Confirms that the keyboard view doesn't have parent view. 1656060efb6d82af1f896d90cb845c8ae07c726f85e1satok ViewParent p = v.getParent(); 1657060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (p != null && p instanceof ViewGroup) { 1658060efb6d82af1f896d90cb845c8ae07c726f85e1satok ((ViewGroup) p).removeView(v); 16595a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 1660060efb6d82af1f896d90cb845c8ae07c726f85e1satok setInputView(v); 1661060efb6d82af1f896d90cb845c8ae07c726f85e1satok } 1662913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1663060efb6d82af1f896d90cb845c8ae07c726f85e1satok updateInputViewShown(); 1664060efb6d82af1f896d90cb845c8ae07c726f85e1satok mHandler.postUpdateSuggestions(); 1665466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1666466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1667409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void clearSuggestions() { 1668dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setSuggestions(SuggestedWords.EMPTY, false); 16697204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1670466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1671466741d8a78965b8509bf527344f289e50873092Mike LeBeau 16722be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard private void setSuggestions(final SuggestedWords words, final boolean isAutoCorrection) { 1673913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) { 1674913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.setSuggestions(words); 1675dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection); 1676466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1677d02783cb63293507e8544ea60d07559092ce83d4Jean Chalard } 1678ec780e2868962bf17f0dfd35d36895f543bde40asatok 167938e535e59676ac4d7bf27026fe3e16fcd9eb292eJean Chalard private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) { 1680ec780e2868962bf17f0dfd35d36895f543bde40asatok // Put a blue underline to a word in TextView which will be auto-corrected. 1681ec780e2868962bf17f0dfd35d36895f543bde40asatok final InputConnection ic = getCurrentInputConnection(); 16822be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard if (ic == null) return; 16832be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard if (mIsAutoCorrectionIndicatorOn != newAutoCorrectionIndicator 16842be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard && mWordComposer.isComposingWord()) { 16852be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard mIsAutoCorrectionIndicatorOn = newAutoCorrectionIndicator; 16862be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard final CharSequence textWithUnderline = 16872be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard getTextWithUnderline(mWordComposer.getTypedWord()); 16882be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard ic.setComposingText(textWithUnderline, 1); 1689ec780e2868962bf17f0dfd35d36895f543bde40asatok } 1690466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1691466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1692409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void updateSuggestions() { 1693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Check if we have a suggestion engine attached. 1694911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa if ((mSuggest == null || !isSuggestionsRequested())) { 1695edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard if (mWordComposer.isComposingWord()) { 1696edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard Log.w(TAG, "Called updateSuggestions but suggestions were not requested!"); 1697edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); 1698edc6395d9bdbb46082c8582ee92f6ba184914d59Jean Chalard } 1699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1701466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1702cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard mHandler.cancelUpdateSuggestions(); 1703cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard mHandler.cancelUpdateBigramPredictions(); 1704cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard 1705196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) { 1706ca26f20fa4903de46e374babbfba8c8a1a5cac93satok setPunctuationSuggestions(); 1707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1709979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 17109f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok // TODO: May need a better way of retrieving previous word 171140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final InputConnection ic = getCurrentInputConnection(); 171240f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final CharSequence prevWord; 171340f7efc172928bdd6048e91421a766abe5b22996Jean Chalard if (null == ic) { 171440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard prevWord = null; 171540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard } else { 171640f7efc172928bdd6048e91421a766abe5b22996Jean Chalard prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); 171740f7efc172928bdd6048e91421a766abe5b22996Jean Chalard } 1718dc5dfe37e06eb1d550d7aa5156cff226334d4e1eJean Chalard 1719dc5dfe37e06eb1d550d7aa5156cff226334d4e1eJean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 17202be7a37acfd498bfc83347597bfb8cb216a310ebJean Chalard // getSuggestedWords handles gracefully a null value of prevWord 17215b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard final SuggestedWords suggestedWords = mSuggest.getSuggestedWords(mWordComposer, 17223708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); 1723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1724a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa // Basically, we update the suggestion strip only when suggestion count > 1. However, 1725a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa // there is an exception: We update the suggestion strip whenever typed word's length 1726f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // is 1 or typed word is found in dictionary, regardless of suggestion count. Actually, 1727f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // in most cases, suggestion count is 1 when typed word's length is 1, but we do always 1728f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // need to clear the previous state when the user starts typing a word (i.e. typed word's 1729f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // length == 1). 17305b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard if (suggestedWords.size() > 1 || typedWord.length() == 1 17315b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard || !suggestedWords.mAllowsToBeAutoCorrected 1732838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard || mSuggestionsView.isShowingAddToDictionaryHint()) { 17335b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard showSuggestions(suggestedWords, typedWord); 1734838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard } else { 1735838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard SuggestedWords previousSuggestions = mSuggestionsView.getSuggestions(); 1736838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard if (previousSuggestions == mSettingsValues.mSuggestPuncList) { 1737838629aea00ce90231df97f1dae3d8273ba80cbdJean Chalard previousSuggestions = SuggestedWords.EMPTY; 1738fe1a6d961cf039357f061482461e4d2e951ad346satok } 17394ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard final ArrayList<SuggestedWords.SuggestedWordInfo> typedWordAndPreviousSuggestions = 174088bf1ba5263f5a5c1df367ddc401db4109ef8677Jean Chalard SuggestedWords.getTypedWordAndPreviousSuggestions( 17414ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalard typedWord, previousSuggestions); 17427d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard final SuggestedWords obsoleteSuggestedWords = 1743bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard new SuggestedWords(typedWordAndPreviousSuggestions, 17442e2519ee914d4bf9462950553840557a4c19faedJean Chalard false /* typedWordValid */, 1745bdf6d1b18b3cebdde5f39d10066ead34be161bafJean Chalard false /* hasAutoCorrectionCandidate */, 1746b5eeb724fc98bb7169683539027d9ba54ffb8b14Jean Chalard false /* allowsToBeAutoCorrected */, 174703a35170751a635332c00bf6c272a0127a255cf6Jean Chalard false /* isPunctuationSuggestions */, 174803a35170751a635332c00bf6c272a0127a255cf6Jean Chalard true /* isObsoleteSuggestions */); 17497d55c891afdf7e74e505acac998a95a9ca7a9ec2Jean Chalard showSuggestions(obsoleteSuggestedWords, typedWord); 17509fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka } 1751979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 17524a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 1753d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard public void showSuggestions(final SuggestedWords suggestedWords, final CharSequence typedWord) { 1754d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard final CharSequence autoCorrection; 17557e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestedWords.size() > 0) { 175668823ae08e820f0951447ed12c1bd32a24333d2eJean Chalard if (suggestedWords.hasAutoCorrectionWord()) { 1757d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = suggestedWords.getWord(1); 1758923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1759d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = typedWord; 1760923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1762d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard autoCorrection = null; 1763923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1764d992fa847da8f232d961ff097857757bfbff73a5Jean Chalard mWordComposer.setAutoCorrection(autoCorrection); 17659b01890254c62a30b079bd9f79a30f9541faf11bJean Chalard final boolean isAutoCorrection = suggestedWords.willAutoCorrect(); 1766dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setSuggestions(suggestedWords, isAutoCorrection); 1767dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setAutoCorrectionIndicator(isAutoCorrection); 1768913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1769923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1770923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1771f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard private void commitCurrentAutoCorrection(final int separatorCodePoint, 1772f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard final InputConnection ic) { 1773913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Complete any pending suggestions query first 1774d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka if (mHandler.hasPendingUpdateSuggestions()) { 1775d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.cancelUpdateSuggestions(); 1776923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project updateSuggestions(); 1777923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1778117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); 1779117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard if (autoCorrection != null) { 1780117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard final String typedWord = mWordComposer.getTypedWord(); 178146798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard if (TextUtils.isEmpty(typedWord)) { 178246798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard throw new RuntimeException("We have an auto-correction but the typed word " 178346798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard + "is empty? Impossible! I must commit suicide."); 178446798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard } 1785f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); 178660adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 178760adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge ResearchLogger.LatinIME_commitCurrentAutoCorrection(typedWord, 178860adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge autoCorrection.toString()); 178960adb8757496fecb8f376a80832c176b35e43d06Kurt Partridge } 17904733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 179166bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD, 179266bb563535dbe3672f99f75bd71763a551444867Jean Chalard separatorCodePoint); 1793c24f66e18007b5aba32bfab8f86eb7f03fa6c1b7Jean Chalard // Add the word to the user history dictionary 1794c24f66e18007b5aba32bfab8f86eb7f03fa6c1b7Jean Chalard addToUserHistoryDictionary(autoCorrection); 1795f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard if (!typedWord.equals(autoCorrection) && null != ic) { 17961c6cf26c3705e845418a29718c034598b52293ccJean Chalard // This will make the correction flash for a short while as a visual clue 17971c6cf26c3705e845418a29718c034598b52293ccJean Chalard // to the user that auto-correction happened. 179896fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasa ic.commitCorrection(new CorrectionInfo(mLastSelectionEnd - typedWord.length(), 179996fdc4dd8426a078500ce1d8a104bde7201bf9b5Ken Wakasa typedWord, autoCorrection)); 18001c6cf26c3705e845418a29718c034598b52293ccJean Chalard } 1801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1804c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 18052e2d6b4d4060ed3b956b4bd4c1f89b5d9c87b525Jean Chalard public void pickSuggestionManually(final int index, final CharSequence suggestion) { 18068cc8f26adfe0f06cebc697dac43a856326cf7afcTadashi G. Takaoka final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); 18074f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett 1808845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) { 1809845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard int firstChar = Character.codePointAt(suggestion, 0); 1810845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard if ((!mSettingsValues.isWeakSpaceStripper(firstChar)) 1811845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard && (!mSettingsValues.isWeakSpaceSwapper(firstChar))) { 1812845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard sendKeyCodePoint(Keyboard.CODE_SPACE); 1813845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 1814845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard } 1815845b24d9d31072b98958c557366617ad1c34f1b7Jean Chalard 1816dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn 1817dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mApplicationSpecifiedCompletions != null 18181b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka && index >= 0 && index < mApplicationSpecifiedCompletions.length) { 1819913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) { 1820913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.clear(); 1821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1822b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1823611a5bdf650f7bc54bf40176f84f1cd9c87aa9aaJean Chalard resetComposingState(true /* alsoResetLastComposedWord */); 1824e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final InputConnection ic = getCurrentInputConnection(); 18259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic != null) { 1826e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; 1827e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard ic.commitCompletion(completionInfo); 18289a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 1829923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 18316a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1832e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput 1833e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard if (suggestion.length() == 1 && isShowingPunctuationList()) { 1834979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Word separators are suggested before the user inputs something. 1835979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // So, LatinImeLogger logs "" as a user's input. 18368cc8f26adfe0f06cebc697dac43a856326cf7afcTadashi G. Takaoka LatinImeLogger.logOnManualSuggestion("", suggestion.toString(), index, suggestedWords); 1837e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard // Rely on onCodeInput to do the complicated swapping/stripping logic consistently. 18382e2d6b4d4060ed3b956b4bd4c1f89b5d9c87b525Jean Chalard final int primaryCode = suggestion.charAt(0); 1839ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok onCodeInput(primaryCode, 1840e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE, 1841e771fc2f1ac7935befcc4d872cc974a47b50fdc7Jean Chalard KeyboardActionListener.SUGGESTION_STRIP_COORDINATE); 18426a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani return; 18436a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 1844af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // We need to log before we commit, because the word composer will store away the user 1845af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard // typed word. 1846af9fe5c5fcad1db22f605e0568c9a77cef178d22Jean Chalard LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), 18478cc8f26adfe0f06cebc697dac43a856326cf7afcTadashi G. Takaoka suggestion.toString(), index, suggestedWords); 18484733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 184966bb563535dbe3672f99f75bd71763a551444867Jean Chalard commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, 185066bb563535dbe3672f99f75bd71763a551444867Jean Chalard LastComposedWord.NOT_A_SEPARATOR); 1851c24f66e18007b5aba32bfab8f86eb7f03fa6c1b7Jean Chalard // Add the word to the user history dictionary 1852c24f66e18007b5aba32bfab8f86eb7f03fa6c1b7Jean Chalard addToUserHistoryDictionary(suggestion); 1853fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mSpaceState = SPACE_STATE_PHANTOM; 1854fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard // TODO: is this necessary? 1855fb684cebe8f5dac1bdb6cfa7085a07ddc66acedeJean Chalard mKeyboardSwitcher.updateShiftState(); 1856979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1857c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // We should show the "Touch again to save" hint if the user pressed the first entry 1858c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND either: 18597f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is no dictionary (we know that because we tried to load it => null != mSuggest 1860c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND mSuggest.hasMainDictionary() is false) 18617f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is a dictionary and the word is not in it 18627f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // Please note that if mSuggest is null, it means that everything is off: suggestion 18637f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // and correction, so we shouldn't try to show the hint 18647f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // We used to look at mCorrectionMode here, but showing the hint should have nothing 18657f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // to do with the autocorrection setting. 1866bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null 1867bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If there is no dictionary the hint should be shown. 1868c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa && (!mSuggest.hasMainDictionary() 1869bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If "suggestion" is not in the dictionary, the hint should be shown. 1870bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok || !AutoCorrection.isValidWord( 1871bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok mSuggest.getUnigramDictionaries(), suggestion, true)); 1872b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 1873406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE, 1874406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard WordComposer.NOT_A_COORDINATE); 1875777118a40a363ccab69a00016d3156066513cb78Jean Chalard if (!showingAddToDictionaryHint) { 1876364da8c618303a7764595d2c15ee034a7671365dKen Wakasa // If we're not showing the "Touch again to save", then show corrections again. 1877979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // In case the cursor position doesn't change, make sure we show the suggestions again. 187841ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard updateBigramPredictions(); 187941ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // Updating the predictions right away may be slow and feel unresponsive on slower 188041ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // terminals. On the other hand if we just postUpdateBigramPredictions() it will 188141ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // take a noticeable delay to update them which may feel uneasy. 188295a6e58ebcd8f44b970a8238cf30e48b10fc4b61Jean Chalard } else { 188388562bec54658840dcce352127bdc15705c20a89Jean Chalard if (mIsUserDictionaryAvailable) { 1884644d33d60ea5a87501274488013d65f55238895eKen Wakasa mSuggestionsView.showAddToDictionaryHint( 1885644d33d60ea5a87501274488013d65f55238895eKen Wakasa suggestion, mSettingsValues.mHintToSaveText); 1886ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka } else { 1887ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1888ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka } 188966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 1890923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1891a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1892979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 18938558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa * Commits the chosen word to the text field and saves it for later retrieval. 1894979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 189566bb563535dbe3672f99f75bd71763a551444867Jean Chalard private void commitChosenWord(final CharSequence bestWord, final int commitType, 189666bb563535dbe3672f99f75bd71763a551444867Jean Chalard final int separatorCode) { 18979351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 18991531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard if (mSettingsValues.mEnableSuggestionSpanInsertion) { 19001531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); 19011531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( 19021531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard this, bestWord, suggestedWords), 1); 19031531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard } else { 19041531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard ic.commitText(bestWord, 1); 19051531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard } 1906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 19070fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // TODO: figure out here if this is an auto-correct or if the best word is actually 19080fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // what user typed. Note: currently this is done much later in 1909bdf89ce5feedb03e67b43f530b1eb9bd44203c63Jean Chalard // LastComposedWord#didCommitTypedWord by string equality of the remembered 19100fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // strings. 191166bb563535dbe3672f99f75bd71763a551444867Jean Chalard mLastComposedWord = mWordComposer.commitWord(commitType, bestWord.toString(), 191266bb563535dbe3672f99f75bd71763a551444867Jean Chalard separatorCode); 1913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 191541ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard public void updateBigramPredictions() { 191689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (mSuggest == null || !isSuggestionsRequested()) 191789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard return; 191889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 191917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (!mSettingsValues.mBigramPredictionEnabled) { 1920cb3320179d39a7983874697a0aa428b127675c9dJean Chalard setPunctuationSuggestions(); 1921cb3320179d39a7983874697a0aa428b127675c9dJean Chalard return; 1922cb3320179d39a7983874697a0aa428b127675c9dJean Chalard } 1923cb3320179d39a7983874697a0aa428b127675c9dJean Chalard 19248e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard final SuggestedWords suggestedWords; 1925a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard if (mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { 1926a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(), 1927a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard mSettingsValues.mWordSeparators); 19280cf422fbb763e2672fb2f9e8e1e8af91d2e87cb3Jean Chalard if (!TextUtils.isEmpty(prevWord)) { 19295b0643f50d8c363296360f3ceaf32f7edc157141Jean Chalard suggestedWords = mSuggest.getBigramPredictions(prevWord); 19300cf422fbb763e2672fb2f9e8e1e8af91d2e87cb3Jean Chalard } else { 19318e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard suggestedWords = null; 19320cf422fbb763e2672fb2f9e8e1e8af91d2e87cb3Jean Chalard } 1933a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard } else { 19348e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard suggestedWords = null; 1935a333ff19ef330c93287cfa0f6568d0cdcd431b04Jean Chalard } 193689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 19378e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard if (null != suggestedWords && suggestedWords.size() > 0) { 193889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Explicitly supply an empty typed word (the no-second-arg version of 193989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // showSuggestions will retrieve the word near the cursor, we don't want that here) 19408e19b1183e4925b7c396de45a5e4e7d67a7b876aJean Chalard showSuggestions(suggestedWords, ""); 194189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 194289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (!isShowingPunctuationList()) setPunctuationSuggestions(); 194389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 194489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 194589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 19467a8dac55278cedd838be325f56b4c52d973c61f5satok public void setPunctuationSuggestions() { 1947dd931c47be1a4fe4cf86c8ad018e479c2cbdf8ceJean Chalard setSuggestions(mSettingsValues.mSuggestPuncList, false); 19487204eab3da916d8873b7eeee4b4528a6b82de19cJean Chalard setAutoCorrectionIndicator(false); 1949913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 19506a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 19516a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1952c24f66e18007b5aba32bfab8f86eb7f03fa6c1b7Jean Chalard private void addToUserHistoryDictionary(final CharSequence suggestion) { 19533ee7d97587ccbbeb8003d2142478337e8d60b2b7Jean Chalard if (TextUtils.isEmpty(suggestion)) return; 1954bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 19550c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be 19560c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // adding words in situations where the user or application really didn't 19570c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // want corrections enabled or learned. 1958979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (!(mCorrectionMode == Suggest.CORRECTION_FULL 1959979f8690967ff5409fe18f5085858ccdb8e0ccf1satok || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) { 1960979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return; 1961979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1962bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 19639ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard if (mUserHistoryDictionary != null) { 196440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final InputConnection ic = getCurrentInputConnection(); 19659ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard final CharSequence prevWord; 196640f7efc172928bdd6048e91421a766abe5b22996Jean Chalard if (null != ic) { 19679ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); 19689ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard } else { 19699ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard prevWord = null; 1970979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 197171f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard final String secondWord; 197271f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard if (mWordComposer.isAutoCapitalized() && !mWordComposer.isMostlyCaps()) { 197371f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard secondWord = suggestion.toString().toLowerCase(mSubtypeSwitcher.getInputLocale()); 197471f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } else { 197571f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard secondWord = suggestion.toString(); 197671f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard } 19779ffb94fa1318f354692fab7abf4775fa14397a96Jean Chalard mUserHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(), 197871f9d30b18e05d7d97d607d1aac3f81c6724abd9Jean Chalard secondWord); 197932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 198032e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 198132e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani 19827a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isCursorTouchingWord() { 19839351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic == null) return false; 19858667bbeab3321e05f518770f7360a3fef52b4407Jean Chalard CharSequence before = ic.getTextBeforeCursor(1, 0); 19868667bbeab3321e05f518770f7360a3fef52b4407Jean Chalard CharSequence after = ic.getTextAfterCursor(1, 0); 19876ec1209a33fe2dc151b86d3f662e22e564e2f4f8Jean Chalard if (!TextUtils.isEmpty(before) && !mSettingsValues.isWordSeparator(before.charAt(0)) 19886ec1209a33fe2dc151b86d3f662e22e564e2f4f8Jean Chalard && !mSettingsValues.isSymbolExcludedFromWordSeparators(before.charAt(0))) { 1989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 19916ec1209a33fe2dc151b86d3f662e22e564e2f4f8Jean Chalard if (!TextUtils.isEmpty(after) && !mSettingsValues.isWordSeparator(after.charAt(0)) 19926ec1209a33fe2dc151b86d3f662e22e564e2f4f8Jean Chalard && !mSettingsValues.isSymbolExcludedFromWordSeparators(after.charAt(0))) { 1993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1994923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return false; 1996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1997a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1998120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // "ic" must not be null 19998ff0564f6a7c78e2fda517ea49b2ac2fa96d0f8eJean Chalard private static boolean sameAsTextBeforeCursor(final InputConnection ic, 20008ff0564f6a7c78e2fda517ea49b2ac2fa96d0f8eJean Chalard final CharSequence text) { 20018ff0564f6a7c78e2fda517ea49b2ac2fa96d0f8eJean Chalard final CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); 2002dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani return TextUtils.equals(text, beforeText); 2003dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani } 2004dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 2005120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // "ic" must not be null 20066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 20076b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Check if the cursor is actually at the end of a word. If so, restart suggestions on this 20086b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * word, else do nothing. 20096b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 20106b1f500da451de56932a8b2a99c63857994ece85Jean Chalard private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord( 20116b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final InputConnection ic) { 20126b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Bail out if the cursor is not at the end of a word (cursor must be preceded by 20136b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // non-whitespace, non-separator, non-start-of-text) 20146b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Example ("|" is the cursor here) : <SOL>"|a" " |a" " | " all get rejected here. 20156b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence textBeforeCursor = ic.getTextBeforeCursor(1, 0); 20166b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (TextUtils.isEmpty(textBeforeCursor) 20176b1f500da451de56932a8b2a99c63857994ece85Jean Chalard || mSettingsValues.isWordSeparator(textBeforeCursor.charAt(0))) return; 20186b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20196b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Bail out if the cursor is in the middle of a word (cursor must be followed by whitespace, 20206b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // separator or end of line/text) 20216b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Example: "test|"<EOL> "te|st" get rejected here 20226b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence textAfterCursor = ic.getTextAfterCursor(1, 0); 20236b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (!TextUtils.isEmpty(textAfterCursor) 20246b1f500da451de56932a8b2a99c63857994ece85Jean Chalard && !mSettingsValues.isWordSeparator(textAfterCursor.charAt(0))) return; 20256b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20266b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Bail out if word before cursor is 0-length or a single non letter (like an apostrophe) 2027fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard // Example: " -|" gets rejected here but "e-|" and "e|" are okay 2028fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard CharSequence word = EditingUtils.getWordAtCursor(ic, mSettingsValues.mWordSeparators); 2029fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard // We don't suggest on leading single quotes, so we have to remove them from the word if 2030fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard // it starts with single quotes. 2031fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard while (!TextUtils.isEmpty(word) && Keyboard.CODE_SINGLE_QUOTE == word.charAt(0)) { 2032fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard word = word.subSequence(1, word.length()); 2033fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard } 20346b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (TextUtils.isEmpty(word)) return; 2035fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard final char firstChar = word.charAt(0); // we just tested that word is not empty 2036fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard if (word.length() == 1 && !Character.isLetter(firstChar)) return; 2037fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard 2038fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard // We only suggest on words that start with a letter or a symbol that is excluded from 2039fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard // word separators (see #handleCharacterWhileInBatchEdit). 2040fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard if (!(isAlphabet(firstChar) 2041fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard || mSettingsValues.isSymbolExcludedFromWordSeparators(firstChar))) { 2042fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard return; 2043fbd1ac80838abb47bca25203f05de3a364356f27Jean Chalard } 20446b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20456b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Okay, we are at the end of a word. Restart suggestions. 20466b1f500da451de56932a8b2a99c63857994ece85Jean Chalard restartSuggestionsOnWordBeforeCursor(ic, word); 20476b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 20486b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20496b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // "ic" must not be null 20506b1f500da451de56932a8b2a99c63857994ece85Jean Chalard private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, 20516b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence word) { 20523708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); 20536b1f500da451de56932a8b2a99c63857994ece85Jean Chalard ic.deleteSurroundingText(word.length(), 0); 20546b1f500da451de56932a8b2a99c63857994ece85Jean Chalard ic.setComposingText(word, 1); 20556b1f500da451de56932a8b2a99c63857994ece85Jean Chalard mHandler.postUpdateSuggestions(); 20566b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 20576b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20586b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // "ic" must not be null 20595935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard private void revertCommit(final InputConnection ic) { 2060b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard final String originallyTypedWord = mLastComposedWord.mTypedWord; 2061cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final CharSequence committedWord = mLastComposedWord.mCommittedWord; 2062cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard final int cancelLength = committedWord.length(); 2063ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok final int separatorLength = LastComposedWord.getSeparatorLength( 2064193d23f40e1556074f323b7bd9695759f4798efeJean Chalard mLastComposedWord.mSeparatorCode); 2065193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // TODO: should we check our saved separator against the actual contents of the text view? 2066890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2067b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard if (mWordComposer.isComposingWord()) { 20685935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit, but we are composing a word"); 2069b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard } 2070890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard final String wordBeforeCursor = 2071193d23f40e1556074f323b7bd9695759f4798efeJean Chalard ic.getTextBeforeCursor(cancelLength + separatorLength, 0) 2072193d23f40e1556074f323b7bd9695759f4798efeJean Chalard .subSequence(0, cancelLength).toString(); 2073cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard if (!TextUtils.equals(committedWord, wordBeforeCursor)) { 20745935950d4431dd7eef18ebc370f2abeb614465d4Jean Chalard throw new RuntimeException("revertCommit check failed: we thought we were " 2075cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard + "reverting \"" + committedWord 2076890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); 2077890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 20788558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa } 2079193d23f40e1556074f323b7bd9695759f4798efeJean Chalard ic.deleteSurroundingText(cancelLength + separatorLength, 0); 2080193d23f40e1556074f323b7bd9695759f4798efeJean Chalard if (0 == separatorLength || mLastComposedWord.didCommitTypedWord()) { 2081193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // This is the case when we cancel a manual pick. 2082193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // We should restart suggestion on the word right away. 208332f0af1fc48f67907f0e731e18359f29e2b1df14Jean Chalard mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); 208432f0af1fc48f67907f0e731e18359f29e2b1df14Jean Chalard ic.setComposingText(originallyTypedWord, 1); 2085193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } else { 2086193d23f40e1556074f323b7bd9695759f4798efeJean Chalard ic.commitText(originallyTypedWord, 1); 2087193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // Re-insert the separator 2088193d23f40e1556074f323b7bd9695759f4798efeJean Chalard sendKeyCodePoint(mLastComposedWord.mSeparatorCode); 2089193d23f40e1556074f323b7bd9695759f4798efeJean Chalard Utils.Stats.onSeparator(mLastComposedWord.mSeparatorCode, WordComposer.NOT_A_COORDINATE, 2090193d23f40e1556074f323b7bd9695759f4798efeJean Chalard WordComposer.NOT_A_COORDINATE); 2091193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // Don't restart suggestion yet. We'll restart if the user deletes the 2092193d23f40e1556074f323b7bd9695759f4798efeJean Chalard // separator. 2093193d23f40e1556074f323b7bd9695759f4798efeJean Chalard } 2094b6b8729374dc68b153f00730c79828532acf1ee5Jean Chalard mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; 2095890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard mHandler.cancelUpdateBigramPredictions(); 2096890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard mHandler.postUpdateSuggestions(); 2097890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2098890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 2099890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard // "ic" must not be null 21002124bc5bf5af31cf3d2789b70ebd2f24c815f5f4Jean Chalard private boolean revertDoubleSpaceWhileInBatchEdit(final InputConnection ic) { 21014733609947c0ec74e460bd714fffca0518ade93aJean Chalard mHandler.cancelDoubleSpacesTimer(); 21024733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Here we test whether we indeed have a period and a space before us. This should not 21034733609947c0ec74e460bd714fffca0518ade93aJean Chalard // be needed, but it's there just in case something went wrong. 21044733609947c0ec74e460bd714fffca0518ade93aJean Chalard final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); 21058ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard if (!". ".equals(textBeforeCursor)) { 210651fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // Theoretically we should not be coming here if there isn't ". " before the 210751fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // cursor, but the application may be changing the text while we are typing, so 210851fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard // anything goes. We should not crash. 210951fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard Log.d(TAG, "Tried to revert double-space combo but we didn't find " 21108ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard + "\". \" just before the cursor."); 211151fd1632f59bd9aaeb5c98ff031f1618e8c31c59Jean Chalard return false; 21128ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard } 21134733609947c0ec74e460bd714fffca0518ade93aJean Chalard ic.deleteSurroundingText(2, 0); 21144733609947c0ec74e460bd714fffca0518ade93aJean Chalard ic.commitText(" ", 1); 21154733609947c0ec74e460bd714fffca0518ade93aJean Chalard return true; 21164733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 21174733609947c0ec74e460bd714fffca0518ade93aJean Chalard 21188fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean revertSwapPunctuation(final InputConnection ic) { 2119120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Here we test whether we indeed have a space and something else before us. This should not 2120120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // be needed, but it's there just in case something went wrong. 2121120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); 2122120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to 2123120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // enter surrogate pairs this code will have been removed. 21248be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard if (TextUtils.isEmpty(textBeforeCursor) 21258be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard || (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))) { 21268be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard // We may only come here if the application is changing the text while we are typing. 21278be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard // This is quite a broken case, but not logically impossible, so we shouldn't crash, 21288be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard // but some debugging log may be in order. 21298be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard Log.d(TAG, "Tried to revert a swap of punctuation but we didn't " 21308ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard + "find a space just before the cursor."); 21318be16f78b10aa4a8975c4068db1b32f81f661a2cJean Chalard return false; 21328ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard } 2133120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.beginBatchEdit(); 2134120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.deleteSurroundingText(2, 0); 2135120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1); 2136120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.endBatchEdit(); 2137120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 2138120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 2139120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 2140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean isWordSeparator(int code) { 214117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard return mSettingsValues.isWordSeparator(code); 2142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean preferCapitalization() { 21459318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa return mWordComposer.isFirstCharCapitalized(); 2146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 214888fc9d44186120f9edc5cf7ec0e2af85260fed04satok // Notify that language or mode have been changed and toggleLanguage will update KeyboardID 2149c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka // according to new language or mode. 2150c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka public void onRefreshKeyboard() { 21511e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // When the device locale is changed in SetupWizard etc., this method may get called via 21521e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // onConfigurationChanged before SoftInputWindow is shown. 21531e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka if (mKeyboardSwitcher.getKeyboardView() != null) { 21541e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // Reload keyboard because the current language has been changed. 21551e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettingsValues); 21561e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka } 21570ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 21583fe263fac6375836c48ce71da29f098b66eb4f11Jean Chalard updateCorrectionMode(); 215917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 2160b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // Since we just changed languages, we should re-evaluate suggestions with whatever word 2161b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // we are currently composing. If we are not composing anything, we may want to display 2162b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard // predictions or punctuation signs (which is done by updateBigramPredictions anyway). 2163b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard if (isCursorTouchingWord()) { 2164b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard mHandler.postUpdateSuggestions(); 2165b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard } else { 2166b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard mHandler.postUpdateBigramPredictions(); 2167b84ee82e66d608151fcf552c82e7765a74e47fb0Jean Chalard } 216836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 216936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 2170564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard public void hapticAndAudioFeedback(final int primaryCode) { 2171544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard mFeedbackManager.hapticAndAudioFeedback(primaryCode, mKeyboardSwitcher.getKeyboardView()); 2172d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka } 2173d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka 21745a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 21752a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onPressKey(int primaryCode) { 2176a5c96f376ad57e78a88942bb618e067054ed818aTadashi G. Takaoka mKeyboardSwitcher.onPressKey(primaryCode); 2177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 21795a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 21802a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka public void onReleaseKey(int primaryCode, boolean withSliding) { 21812a88440419f49d100c73e067a823390f64aba3b1Tadashi G. Takaoka mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding); 21828d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv 21838d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv // If accessibility is on, ensure the user receives keyboard state updates. 21848d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) { 21858d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv switch (primaryCode) { 21868d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case Keyboard.CODE_SHIFT: 21878d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifyShiftState(); 21888d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 21898d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 21908d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv AccessibleKeyboardViewProxy.getInstance().notifySymbolsState(); 21918d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv break; 21928d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 21938d4f0d5d1df2e0ae0b6ac332fd6661b7fa903186alanv } 2194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2195a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2196123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka // receive ringer mode change and network state change. 2197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private BroadcastReceiver mReceiver = new BroadcastReceiver() { 2198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 2199923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onReceive(Context context, Intent intent) { 2200123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final String action = intent.getAction(); 2201564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2202123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka mSubtypeSwitcher.onNetworkStateChanged(intent); 220321af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 220421af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard mFeedbackManager.onRingerModeChanged(); 2205123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } 2206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 2208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2209e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani private void updateCorrectionMode() { 22109f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok // TODO: cleanup messy flags 2211f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled 2212dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && !mInputAttributes.mInputTypeNoAutoCorrect; 2213283b0c2b642030539ba3e41f3f54b6aed6bb9e2dJean Chalard mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE; 2214283b0c2b642030539ba3e41f3f54b6aed6bb9e2dJean Chalard mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect) 2215979f8690967ff5409fe18f5085858ccdb8e0ccf1satok ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode; 2216e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani } 2217e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani 22182ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka private void updateSuggestionVisibility(final Resources res) { 22190fe3611bee5095e7bd0fff2d0fdf8d5a13379132Jean Chalard final String suggestionVisiblityStr = mSettingsValues.mShowSuggestionsSetting; 22207599cfea4a2d56f4779452ec8e8742f7b9629cc0satok for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { 2221458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa if (suggestionVisiblityStr.equals(res.getString(visibility))) { 22227599cfea4a2d56f4779452ec8e8742f7b9629cc0satok mSuggestionVisibility = visibility; 22237599cfea4a2d56f4779452ec8e8742f7b9629cc0satok break; 22247599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 22257599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 22267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 22277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 2228466741d8a78965b8509bf527344f289e50873092Mike LeBeau protected void launchSettings() { 2229cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa launchSettingsClass(Settings.class); 2230466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2231466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2232bf96661d33d0126adb60a48880ceba1ff055d4a4satok public void launchDebugSettings() { 2233cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa launchSettingsClass(DebugSettings.class); 2234bf96661d33d0126adb60a48880ceba1ff055d4a4satok } 2235bf96661d33d0126adb60a48880ceba1ff055d4a4satok 2236cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa protected void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) { 2237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project handleClose(); 2238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Intent intent = new Intent(); 2239466741d8a78965b8509bf527344f289e50873092Mike LeBeau intent.setClass(LatinIME.this, settingsClass); 2240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project startActivity(intent); 2242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showSubtypeSelectorAndSettings() { 224585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 224685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 224785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka // TODO: Should use new string "Select active input modes". 224885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.language_selection_title), 224985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.english_ime_settings), 225085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 225185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 22522fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka @Override 22532fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka public void onClick(DialogInterface di, int position) { 22542fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka di.dismiss(); 22552fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka switch (position) { 225685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 22572cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok Intent intent = CompatUtils.getInputLanguageSelectionIntent( 2258cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka SubtypeUtils.getInputMethodId(getPackageName()), 22592a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Intent.FLAG_ACTIVITY_NEW_TASK 22602fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 22612fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 22622fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka startActivity(intent); 22632fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2264aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa case 1: 2265aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa launchSettings(); 2266aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa break; 22672fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 22682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 226985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2270bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2271bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2272bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2273bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka showOptionDialogInternal(builder.create()); 22742fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 2275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 227613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka private void showOptionDialogInternal(AlertDialog dialog) { 227713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final IBinder windowToken = KeyboardSwitcher.getInstance().getKeyboardView() 227813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka .getWindowToken(); 227913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka if (windowToken == null) return; 228013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 228113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCancelable(true); 228213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.setCanceledOnTouchOutside(true); 228313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 228413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final Window window = dialog.getWindow(); 228513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka final WindowManager.LayoutParams lp = window.getAttributes(); 228613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.token = windowToken; 228713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 228813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.setAttributes(lp); 228913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 229013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 229113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka mOptionsDialog = dialog; 229213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka dialog.show(); 229313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka } 229413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka 22957e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 22967e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 2297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.dump(fd, fout, args); 2298a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project final Printer p = new PrintWriterPrinter(fout); 2300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println("LatinIME state :"); 23013708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2302df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; 2303df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka p.println(" Keyboard mode = " + keyboardMode); 2304dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn); 2305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println(" mCorrectionMode=" + mCorrectionMode); 23064d0f03bd66742ee292da81a3e025e119f28b6940Jean Chalard p.println(" isComposingWord=" + mWordComposer.isComposingWord()); 230717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard p.println(" mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled); 230817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard p.println(" mSoundOn=" + mSettingsValues.mSoundOn); 230917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn); 2310240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn); 23116fa003ee234c6e2ca6cd9ec555221ac5c71a5405Jean Chalard p.println(" mInputAttributes=" + mInputAttributes.toString()); 2312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 2314