LatinIME.java revision 1ef6fc7e1519cedec9e84a64968bfba4212d0436
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; 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService; 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager; 30123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager; 31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug; 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message; 33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock; 34bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager; 36e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils; 38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log; 39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter; 40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer; 4166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 448e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup; 458e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo; 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo; 48466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText; 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection; 50c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 515ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils; 52c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils; 53c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.EditorInfoCompatUtils; 54c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputConnectionCompatUtils; 55c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper; 56c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodServiceCompatWrapper; 57c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputTypeCompatUtils; 581fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils; 5928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasaimport com.android.inputmethod.compat.VibratorCompatWrapper; 60c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.LanguageSwitcherProxy; 61c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.VoiceProxy; 6283ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasaimport com.android.inputmethod.keyboard.Key; 63c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 656b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId; 66c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 67f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 68c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView; 698c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionsView; 70923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 71466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor; 72466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter; 73466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale; 74466741d8a78965b8509bf527344f289e50873092Mike LeBeau 75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard. 77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 78c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaokapublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener, 79913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka SuggestionsView.Listener { 808efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka private static final String TAG = LatinIME.class.getSimpleName(); 81409220583333bdf06290dd9fd42f91b5c0d1b11asatok private static final boolean TRACE = false; 829e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka private static boolean DEBUG; 83a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 848efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka /** 858efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * The private IME option used to indicate that no microphone should be 868efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * shown for a given text field. For instance, this is specified by the 878efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * search dialog when the dialog is already showing a voice search button. 888efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * 898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed. 908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka */ 9110dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok @SuppressWarnings("dep-ann") 928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm"; 938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka 948efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka /** 958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * The private IME option used to indicate that no microphone should be 968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * shown for a given text field. For instance, this is specified by the 978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka * search dialog when the dialog is already showing a voice search button. 988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka */ 994199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey"; 1004199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka 1014199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka /** 1024199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka * The private IME option used to indicate that no settings key should be 1034199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka * shown for a given text field. 1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka */ 1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey"; 1068efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka 1071ef6fc7e1519cedec9e84a64968bfba4212d0436Tadashi G. Takaoka // TODO: Remove this private option. 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 /** 118af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka * The subtype extra value used to indicate that the subtype keyboard layout is capable for 119af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka * typing ASCII characters. 120af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka */ 121af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable"; 122af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka 123d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka /** 124294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima * The subtype extra value used to indicate that the subtype keyboard layout supports touch 125294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima * position correction. 126294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima */ 127294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima public static final String SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION = 128294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima "SupportTouchPositionCorrection"; 129294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima /** 130d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka * The subtype extra value used to indicate that the subtype keyboard layout should be loaded 131d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka * from the specified locale. 132d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka */ 133d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE = "KeyboardLocale"; 134d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka 1359e347d3d448e48229c46aad394ec9bd60cd5807bsatok private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100; 136fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa 137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // How many continuous deletes at which to start deleting at a higher speed. 138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int DELETE_ACCELERATE_AT = 20; 139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Key events coming any faster than this are long-presses. 140d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani private static final int QUICK_PRESS = 200; 141a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 14259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private static final int PENDING_IMS_CALLBACK_DURATION = 800; 143055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 144cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /** 145cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * The name of the scheme used by the Package Manager to warn of a new package installation, 146cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * replacement or removal. 147cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard */ 148cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private static final String SCHEME_PACKAGE = "package"; 149cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 1500fe3611bee5095e7bd0fff2d0fdf8d5a13379132Jean Chalard // TODO: migrate this to SettingsValues 1517599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private int mSuggestionVisibility; 1527599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE 1537599cfea4a2d56f4779452ec8e8742f7b9629cc0satok = R.string.prefs_suggestion_visibility_show_value; 1547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE 1557599cfea4a2d56f4779452ec8e8742f7b9629cc0satok = R.string.prefs_suggestion_visibility_show_only_portrait_value; 1567599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE 1577599cfea4a2d56f4779452ec8e8742f7b9629cc0satok = R.string.prefs_suggestion_visibility_hide_value; 1587599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1597599cfea4a2d56f4779452ec8e8742f7b9629cc0satok private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] { 1607599cfea4a2d56f4779452ec8e8742f7b9629cc0satok SUGGESTION_VISIBILILTY_SHOW_VALUE, 1617599cfea4a2d56f4779452ec8e8742f7b9629cc0satok SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE, 1627599cfea4a2d56f4779452ec8e8742f7b9629cc0satok SUGGESTION_VISIBILILTY_HIDE_VALUE 1637599cfea4a2d56f4779452ec8e8742f7b9629cc0satok }; 1647599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 165120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Magic space: a space that should disappear on space/apostrophe insertion, move after the 166120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // punctuation on punctuation insertion, and become a real space on alpha char insertion. 167ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa // Weak space: a space that should be swapped only by suggestion strip punctuation. 168120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Double space: the state where the user pressed space twice quickly, which LatinIME 169120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // resolved as period-space. Undoing this converts the period to a space. 170120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Swap punctuation: the state where a (weak or magic) space and a punctuation from the 171120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // suggestion strip have just been swapped. Undoing this swaps them back. 172120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_NONE = 0; 173120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_DOUBLE = 1; 174120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_SWAP_PUNCTUATION = 2; 175120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_MAGIC = 3; 176120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private static final int SPACE_STATE_WEAK = 4; 177120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 178120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Current space state of the input method. This can be any of the above constants. 179120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private int mSpaceState; 180126698fdd256a2e3734634d3b923cabd800064baJean Chalard 1817a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard private SettingsValues mSettingsValues; 18280b66bb166f7f45adfcadcb84788477df9930828Jean Chalard private InputAttributes mInputAttributes; 18317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 184d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka private View mExtractArea; 185abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka private View mKeyPreviewBackingView; 186913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private View mSuggestionsContainer; 187913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private SuggestionsView mSuggestionsView; 188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private Suggest mSuggest; 1891b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private CompletionInfo[] mApplicationSpecifiedCompletions; 190a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 191610f1dc8553cf2ed97e763a06a19380c4a6cd636satok private InputMethodManagerCompatWrapper mImm; 1922fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private Resources mResources; 1932fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private SharedPreferences mPrefs; 19471c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka private KeyboardSwitcher mKeyboardSwitcher; 1950ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private SubtypeSwitcher mSubtypeSwitcher; 196b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok private VoiceProxy mVoiceProxy; 197a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private UserDictionary mUserDictionary; 199979f8690967ff5409fe18f5085858ccdb8e0ccf1satok private UserBigramDictionary mUserBigramDictionary; 200f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard private UserUnigramDictionary mUserUnigramDictionary; 20188562bec54658840dcce352127bdc15705c20a89Jean Chalard private boolean mIsUserDictionaryAvailable; 20236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 2039318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa private WordComposer mWordComposer = new WordComposer(); 204409220583333bdf06290dd9fd42f91b5c0d1b11asatok 20579efbed76f638be298493107fa2d0cd1b5eb529esatok private int mCorrectionMode; 206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Keep track of the last selection range to decide if we need to show word alternatives 20779efbed76f638be298493107fa2d0cd1b5eb529esatok private int mLastSelectionStart; 20879efbed76f638be298493107fa2d0cd1b5eb529esatok private int mLastSelectionEnd; 209979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2104733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't 2114733609947c0ec74e460bd714fffca0518ade93aJean Chalard // "expect" it, it means the user actually moved the cursor. 2124733609947c0ec74e460bd714fffca0518ade93aJean Chalard private boolean mExpectingUpdateSelection; 213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private int mDeleteCount; 214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private long mLastKeyTime; 215a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private AudioManager mAudioManager; 21717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard private boolean mSilentModeOn; // System-wide current configuration 218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 21928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa private VibratorCompatWrapper mVibrator; 22028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 221b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok // TODO: Move this flag to VoiceProxy 22281c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani private boolean mConfigurationChanging; 223466741d8a78965b8509bf527344f289e50873092Mike LeBeau 22438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Member variables for remembering the current device orientation. 22538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka private int mDisplayOrientation; 22638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 227cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Object for reacting to adding/removing a dictionary pack. 228cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard private BroadcastReceiver mDictionaryPackInstallReceiver = 229cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard new DictionaryPackInstallBroadcastReceiver(this); 230cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 231dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Keeps track of most recently inserted text (multi-character key) for reverting 232dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani private CharSequence mEnteredText; 233dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 234604d80c67185954d4691ac775be59c499eee3b1csatok private final ComposingStateManager mComposingStateManager = 235fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok ComposingStateManager.getInstance(); 236604d80c67185954d4691ac775be59c499eee3b1csatok 2374f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public final UIHandler mHandler = new UIHandler(this); 238d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 2394f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> { 240d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTIONS = 0; 24145f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_UPDATE_SHIFT_STATE = 1; 24245f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_VOICE_RESULTS = 2; 24345f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3; 24445f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 4; 24545f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard private static final int MSG_SPACE_TYPED = 5; 24693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka private static final int MSG_SET_BIGRAM_PREDICTIONS = 6; 24793246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka private static final int MSG_PENDING_IMS_CALLBACK = 7; 248175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 24910dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayBeforeFadeoutLanguageOnSpacebar; 25010dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateSuggestions; 25110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDelayUpdateShiftState; 25210dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private int mDurationOfFadeoutLanguageOnSpacebar; 25310dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private float mFinalFadeoutFactorOfLanguageOnSpacebar; 25410dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka private long mDoubleSpacesTurnIntoPeriodTimeout; 25538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 2564f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UIHandler(LatinIME outerInstance) { 2574f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 25810dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka } 259175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka 26010dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka public void onCreate() { 26110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka final Resources res = getOuterInstance().getResources(); 262175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger( 263175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_delay_before_fadeout_language_on_spacebar); 264175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateSuggestions = 265175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_suggestions); 266175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayUpdateShiftState = 267175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka res.getInteger(R.integer.config_delay_update_shift_state); 268175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDurationOfFadeoutLanguageOnSpacebar = res.getInteger( 269175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_duration_of_fadeout_language_on_spacebar); 270175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger( 271175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f; 272175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDoubleSpacesTurnIntoPeriodTimeout = res.getInteger( 273175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka R.integer.config_double_spaces_turn_into_period_timeout); 2744f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 2754f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void handleMessage(Message msg) { 2784f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 2794f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher; 280c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka final LatinKeyboardView inputView = switcher.getKeyboardView(); 281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (msg.what) { 282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SUGGESTIONS: 2834f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.updateSuggestions(); 284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_UPDATE_SHIFT_STATE: 286de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka switcher.updateShiftState(); 287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 288cb3320179d39a7983874697a0aa428b127675c9dJean Chalard case MSG_SET_BIGRAM_PREDICTIONS: 2894f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.updateBigramPredictions(); 29089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard break; 291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka case MSG_VOICE_RESULTS: 2924f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization() 293de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked())); 294de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka break; 295de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR: 29623d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka setSpacebarTextFadeFactor(inputView, 29723d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka (1.0f + mFinalFadeoutFactorOfLanguageOnSpacebar) / 2, 2983708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka (Keyboard)msg.obj); 299de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj), 300175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDurationOfFadeoutLanguageOnSpacebar); 301de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka break; 302de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka case MSG_DISMISS_LANGUAGE_ON_SPACEBAR: 30323d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka setSpacebarTextFadeFactor(inputView, mFinalFadeoutFactorOfLanguageOnSpacebar, 3043708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka (Keyboard)msg.obj); 305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka break; 306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 309d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void postUpdateSuggestions() { 310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTIONS); 311175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), mDelayUpdateSuggestions); 312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateSuggestions() { 315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTIONS); 316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public boolean hasPendingUpdateSuggestions() { 319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka return hasMessages(MSG_UPDATE_SUGGESTIONS); 320d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 321d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 322d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void postUpdateShiftKeyState() { 323d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 324175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState); 325d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 326d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 327d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void cancelUpdateShiftState() { 328d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka removeMessages(MSG_UPDATE_SHIFT_STATE); 329d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 330d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka 331cb3320179d39a7983874697a0aa428b127675c9dJean Chalard public void postUpdateBigramPredictions() { 332cb3320179d39a7983874697a0aa428b127675c9dJean Chalard removeMessages(MSG_SET_BIGRAM_PREDICTIONS); 333175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS), mDelayUpdateSuggestions); 33489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 33589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 336cb3320179d39a7983874697a0aa428b127675c9dJean Chalard public void cancelUpdateBigramPredictions() { 337cb3320179d39a7983874697a0aa428b127675c9dJean Chalard removeMessages(MSG_SET_BIGRAM_PREDICTIONS); 33889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 33989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 340d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka public void updateVoiceResults() { 341d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka sendMessage(obtainMessage(MSG_VOICE_RESULTS)); 342d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka } 343de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka 34423d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka private static void setSpacebarTextFadeFactor(LatinKeyboardView inputView, 3453708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka float fadeFactor, Keyboard oldKeyboard) { 34623d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka if (inputView == null) return; 34723d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka final Keyboard keyboard = inputView.getKeyboard(); 3483708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka if (keyboard == oldKeyboard) { 3494112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka inputView.updateSpacebar(fadeFactor, 3504112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka SubtypeSwitcher.getInstance().needsToDisplayLanguage( 3514112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka keyboard.mId.mLocale)); 35223d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka } 35323d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka } 35423d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka 355d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka public void startDisplayLanguageOnSpacebar(boolean localeChanged) { 3564f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final LatinIME latinIme = getOuterInstance(); 357de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR); 358de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR); 359c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView(); 360de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka if (inputView != null) { 3613708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = latinIme.mKeyboardSwitcher.getKeyboard(); 362c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // The language is always displayed when the delay is negative. 363c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka final boolean needsToDisplayLanguage = localeChanged 364175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka || mDelayBeforeFadeoutLanguageOnSpacebar < 0; 365de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka // The language is never displayed when the delay is zero. 366175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka if (mDelayBeforeFadeoutLanguageOnSpacebar != 0) { 36723d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka setSpacebarTextFadeFactor(inputView, 36823d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka needsToDisplayLanguage ? 1.0f : mFinalFadeoutFactorOfLanguageOnSpacebar, 36923d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka keyboard); 37017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 371c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // The fadeout animation will start when the delay is positive. 372175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka if (localeChanged && mDelayBeforeFadeoutLanguageOnSpacebar > 0) { 373de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard), 374175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka mDelayBeforeFadeoutLanguageOnSpacebar); 375de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka } 376de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka } 377de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka } 378fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 379fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void startDoubleSpacesTimer() { 380fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka removeMessages(MSG_SPACE_TYPED); 381175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED), mDoubleSpacesTurnIntoPeriodTimeout); 382fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 383fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 384fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public void cancelDoubleSpacesTimer() { 385fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka removeMessages(MSG_SPACE_TYPED); 386fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 387fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka 388fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka public boolean isAcceptingDoubleSpaces() { 389fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka return hasMessages(MSG_SPACE_TYPED); 390fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka } 39138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 39259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Working variables for the following methods. 39359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mIsOrientationChanging; 39459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mPendingSuccesiveImsCallback; 39559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingStartInput; 39659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInputView; 39759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private boolean mHasPendingFinishInput; 398e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private EditorInfo mAppliedEditorInfo; 39959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 40059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void startOrientationChanging() { 401dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka removeMessages(MSG_PENDING_IMS_CALLBACK); 402dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka resetPendingImsCallback(); 40359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = true; 404055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 405f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka if (latinIme.isInputViewShown()) { 406f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka latinIme.mKeyboardSwitcher.saveKeyboardState(); 407f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka } 40859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 40959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 41059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void resetPendingImsCallback() { 41159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = false; 41259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = false; 41359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = false; 41459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 41559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 416e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void executePendingImsCallback(LatinIME latinIme, EditorInfo editorInfo, 41759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka boolean restarting) { 41859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInputView) 41959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(mHasPendingFinishInput); 42059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingFinishInput) 42159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 42259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mHasPendingStartInput) 423e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 42459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka resetPendingImsCallback(); 42559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 42659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 427e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 42859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 42959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the second onStartInput after orientation changed. 43059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingStartInput = true; 43159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 43259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (mIsOrientationChanging && restarting) { 43359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // This is the first onStartInput after orientation changed. 43459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mIsOrientationChanging = false; 43559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mPendingSuccesiveImsCallback = true; 43659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 43759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 438e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 439e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputInternal(editorInfo, restarting); 440055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 441055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 442055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 443e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 4446b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK) 4456b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) { 446e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // Typically this is the second onStartInputView after orientation changed. 447e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 448e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } else { 449e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka if (mPendingSuccesiveImsCallback) { 450e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka // This is the first onStartInputView after orientation changed. 451e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mPendingSuccesiveImsCallback = false; 452e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka resetPendingImsCallback(); 453e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK), 454e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka PENDING_IMS_CALLBACK_DURATION); 455e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 456e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 457e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka executePendingImsCallback(latinIme, editorInfo, restarting); 458e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka latinIme.onStartInputViewInternal(editorInfo, restarting); 459e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = editorInfo; 460e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka } 46159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 46259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 46359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 46459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 46559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInputView after orientation changed. 46659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInputView = true; 46759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 46859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 46959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputViewInternal(finishingInput); 470e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mAppliedEditorInfo = null; 47138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 47238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 473ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka 47459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 47559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka if (hasMessages(MSG_PENDING_IMS_CALLBACK)) { 47659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka // Typically this is the first onFinishInput after orientation changed. 47759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHasPendingFinishInput = true; 47859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } else { 47959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka final LatinIME latinIme = getOuterInstance(); 48059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka executePendingImsCallback(latinIme, null, false); 48159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka latinIme.onFinishInputInternal(); 482ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 483ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka } 48438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka } 48538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 4867e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 4877e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka public void onCreate() { 48827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 48927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa mPrefs = prefs; 49027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa LatinImeLogger.init(this, prefs); 4916d9021527a38ba1e94225020389621a0d7227aa1satok LanguageSwitcherProxy.init(this, prefs); 492bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka InputMethodManagerCompatWrapper.init(this); 493ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka SubtypeSwitcher.init(this); 49427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa KeyboardSwitcher.init(this, prefs); 4952ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka AccessibilityUtils.init(this); 496363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onCreate(); 498363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 499bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka mImm = InputMethodManagerCompatWrapper.getInstance(); 5000ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 5010ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok mKeyboardSwitcher = KeyboardSwitcher.getInstance(); 50228f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa mVibrator = VibratorCompatWrapper.getInstance(this); 50310dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka mHandler.onCreate(); 5049e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka DEBUG = LatinImeLogger.sDBG; 505363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka 506363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka final Resources res = getResources(); 507363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka mResources = res; 508fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard 50928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa loadSettings(); 51028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa 511dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard // TODO: remove the following when it's not needed by updateCorrectionMode() any more 512644c8b7c96627199c13297082e4566adae159bf3Jean Chalard mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */); 5139502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 514979f8690967ff5409fe18f5085858ccdb8e0ccf1satok boolean tryGC = true; 5159502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 516979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 5170ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 518979f8690967ff5409fe18f5085858ccdb8e0ccf1satok tryGC = false; 519979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (OutOfMemoryError e) { 5209502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e); 521979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 523979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 524f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = res.getConfiguration().orientation; 525b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 526cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Register to receive ringer mode change and network state change. 527cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard // Also receive installation and removal of a dictionary pack. 528123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final IntentFilter filter = new IntentFilter(); 529123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); 530123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project registerReceiver(mReceiver, filter); 532b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy = VoiceProxy.init(this, prefs, mHandler); 533cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 534cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final IntentFilter packageFilter = new IntentFilter(); 535cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 536cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 537cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard packageFilter.addDataScheme(SCHEME_PACKAGE); 538cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, packageFilter); 539646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard 540646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard final IntentFilter newDictFilter = new IntentFilter(); 541646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard newDictFilter.addAction( 542646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION); 543646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard registerReceiver(mDictionaryPackInstallReceiver, newDictFilter); 544923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 54536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 54617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // Has to be package-visible for unit tests 54717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard /* package */ void loadSettings() { 54817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this); 54917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 5507a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard mSettingsValues = new SettingsValues(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr()); 55114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary()); 55217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 55317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 5540ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private void initSuggest() { 555cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); 556ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); 55736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 558309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard final Resources res = mResources; 559ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard final Locale savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale); 56014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard final ContactsDictionary oldContactsDictionary; 56136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani if (mSuggest != null) { 56214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard oldContactsDictionary = mSuggest.getContactsDictionary(); 56336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani mSuggest.close(); 56414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 56514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard oldContactsDictionary = null; 56636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 567979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 5688efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka int mainDicResId = Utils.getMainDictionaryResourceId(res); 569cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard mSuggest = new Suggest(this, mainDicResId, keyboardLocale); 57017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSettingsValues.mAutoCorrectEnabled) { 57117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); 57217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard } 573e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 574cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard mUserDictionary = new UserDictionary(this, localeStr); 575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mSuggest.setUserDictionary(mUserDictionary); 57688562bec54658840dcce352127bdc15705c20a89Jean Chalard mIsUserDictionaryAvailable = mUserDictionary.isEnabled(); 577e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 57814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard resetContactsDictionary(oldContactsDictionary); 579e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 580f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard mUserUnigramDictionary 581f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard = new UserUnigramDictionary(this, this, localeStr, Suggest.DIC_USER_UNIGRAM); 582f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard mSuggest.setUserUnigramDictionary(mUserUnigramDictionary); 583e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 584f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard mUserBigramDictionary 585f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER_BIGRAM); 586e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.setUserBigramDictionary(mUserBigramDictionary); 587e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa 588e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani updateCorrectionMode(); 58936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 590ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard LocaleUtils.setSystemLocale(res, savedLocale); 591923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 59236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 59314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard /** 59414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * Resets the contacts dictionary in mSuggest according to the user settings. 59514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 59614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * This method takes an optional contacts dictionary to use. Since the contacts dictionary 59714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * does not depend on the locale, it can be reused across different instances of Suggest. 59814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * The dictionary will also be opened or closed as necessary depending on the settings. 59914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * 60014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard * @param oldContactsDictionary an optional dictionary to use, or null 60114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard */ 60214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard private void resetContactsDictionary(final ContactsDictionary oldContactsDictionary) { 60314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard final boolean shouldSetDictionary = (null != mSuggest && mSettingsValues.mUseContactsDict); 60414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 60514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard final ContactsDictionary dictionaryToUse; 60614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (!shouldSetDictionary) { 60714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the dictionary is closed. If it is already closed, this is a no-op, 60814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // so it's safe to call it anyways. 60914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != oldContactsDictionary) oldContactsDictionary.close(); 61014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = null; 61114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else if (null != oldContactsDictionary) { 61214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // Make sure the old contacts dictionary is opened. If it is already open, this is a 61314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard // no-op, so it's safe to call it anyways. 61414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard oldContactsDictionary.reopen(this); 61514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = oldContactsDictionary; 61614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } else { 61714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS); 61814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 61914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard 62014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard if (null != mSuggest) { 62114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard mSuggest.setContactsDictionary(dictionaryToUse); 62214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard } 623699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard } 624699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard 625cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard /* package private */ void resetSuggestMainDict() { 626cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); 627ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); 628cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard int mainDicResId = Utils.getMainDictionaryResourceId(mResources); 629cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard mSuggest.resetMainDict(this, mainDicResId, keyboardLocale); 630cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard } 631cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 632466741d8a78965b8509bf527344f289e50873092Mike LeBeau @Override 633466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onDestroy() { 634e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa if (mSuggest != null) { 635e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest.close(); 636e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa mSuggest = null; 637979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project unregisterReceiver(mReceiver); 639cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard unregisterReceiver(mDictionaryPackInstallReceiver); 640b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.destroy(); 641979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 642979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.onDestroy(); 643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onDestroy(); 644923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 646923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 647923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onConfigurationChanged(Configuration conf) { 648dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka mSubtypeSwitcher.onConfigurationChanged(conf); 649604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.onFinishComposingText(); 650b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani // If orientation changed while predicting, commit the change 651f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka if (mDisplayOrientation != conf.orientation) { 652f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mDisplayOrientation = conf.orientation; 653f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka mHandler.startOrientationChanging(); 6549351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 655466741d8a78965b8509bf527344f289e50873092Mike LeBeau commitTyped(ic); 656466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (ic != null) ic.finishComposingText(); // For voice input 6572fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka if (isShowingOptionDialog()) 6582fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka mOptionsDialog.dismiss(); 659b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 6608b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka 66181c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani mConfigurationChanging = true; 662923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onConfigurationChanged(conf); 663b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.onConfigurationChanged(conf); 66481c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani mConfigurationChanging = false; 66588fc9d44186120f9edc5cf7ec0e2af85260fed04satok 66688fc9d44186120f9edc5cf7ec0e2af85260fed04satok // This will work only when the subtype is not supported. 66788fc9d44186120f9edc5cf7ec0e2af85260fed04satok LanguageSwitcherProxy.onConfigurationChanged(conf); 668923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 669b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 670923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 671923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public View onCreateInputView() { 6726c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka return mKeyboardSwitcher.onCreateInputView(); 6736c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka } 6746c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka 6756c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka @Override 6766c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka public void setInputView(View view) { 6776c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka super.setInputView(view); 678d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka mExtractArea = getWindow().getWindow().getDecorView() 679d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka .findViewById(android.R.id.extractArea); 680abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); 681913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer = view.findViewById(R.id.suggestions_container); 682913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view); 683913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) 684913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.setListener(this, view); 685f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka if (LatinImeLogger.sVISUALDEBUG) { 686f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka mKeyPreviewBackingView.setBackgroundColor(0x10FF0000); 687f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka } 688923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 689923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 690923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 691c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public void setCandidatesView(View view) { 692c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka // To ensure that CandidatesView will never be set. 693c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return; 694923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 695923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 696a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker @Override 697e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInput(EditorInfo editorInfo, boolean restarting) { 698e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInput(editorInfo, restarting); 69959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 70059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 70159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 702e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka public void onStartInputView(EditorInfo editorInfo, boolean restarting) { 703e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mHandler.onStartInputView(editorInfo, restarting); 70459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 70559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 70659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 70759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInputView(boolean finishingInput) { 70859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInputView(finishingInput); 70959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 71038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka 71159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka @Override 71259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka public void onFinishInput() { 71359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka mHandler.onFinishInput(); 71459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 71559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 716e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputInternal(EditorInfo editorInfo, boolean restarting) { 717e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInput(editorInfo, restarting); 71859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka } 71959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka 720e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka private void onStartInputViewInternal(EditorInfo editorInfo, boolean restarting) { 721e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka super.onStartInputView(editorInfo, restarting); 72245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 723c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka LatinKeyboardView inputView = switcher.getKeyboardView(); 7248e09172df1bb176cc899940862c56bed9b9aec4esatok 72589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (DEBUG) { 726e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka Log.d(TAG, "onStartInputView: editorInfo:" + ((editorInfo == null) ? "none" 727f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka : String.format("inputType=0x%08x imeOptions=0x%08x", 728e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka editorInfo.inputType, editorInfo.imeOptions))); 729910b73127fa207dd26ec8124000262523b0aac0csatok } 7307ef235f53f2291f22ddf8c56be9860a218b25bbbTadashi G. Takaoka LatinImeLogger.onStartInputView(editorInfo); 731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In landscape mode, this method gets called without the input view being created. 732979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (inputView == null) { 733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 736b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette // Forward this event to the accessibility utilities, if enabled. 737b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance(); 738b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette if (accessUtils.isTouchExplorationEnabled()) { 739e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka accessUtils.onStartInputViewInternal(editorInfo, restarting); 740b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette } 741b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette 7428d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka mSubtypeSwitcher.updateParametersOnStartInputView(); 7434ab730dbd34fad323063f2ffd31ce33de746668dsatok 744055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to 745055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka // know now whether this is a password text field, because we need to know now whether we 746055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka // want to enable the voice button. 747055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka final VoiceProxy voiceIme = mVoiceProxy; 748e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka final int inputType = (editorInfo != null) ? editorInfo.inputType : 0; 7493be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType) 7503be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)); 751c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 752b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // The EditorInfo might have a flag that affects fullscreen mode. 753b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka // Note: This call should be done by InputMethodService? 754b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka updateFullscreenMode(); 75580b66bb166f7f45adfcadcb84788477df9930828Jean Chalard mInputAttributes = new InputAttributes(editorInfo, isFullscreenMode()); 756ccc35f7fa74860a8d737a4e9ff01fc0168dd329dJean Chalard mApplicationSpecifiedCompletions = null; 757c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 758c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.closing(); 759c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mEnteredText = null; 7603651220327c051d8017045aa5e8919461507b3f8Jean Chalard mWordComposer.reset(); 761c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mDeleteCount = 0; 762120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 763c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 76417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 76517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard updateCorrectionMode(); 7662ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka updateSuggestionVisibility(mResources); 76717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 76817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) { 76917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); 770549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka } 771e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka mVoiceProxy.loadSettings(editorInfo, mPrefs); 77217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard // This will work only when the subtype is not supported. 77317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard LanguageSwitcherProxy.loadSettings(); 77417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard 775c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (mSubtypeSwitcher.isKeyboardMode()) { 776e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka switcher.loadKeyboard(editorInfo, mSettingsValues); 777c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 778c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 779913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) 780913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.clear(); 781913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShownInternal( 782913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka isSuggestionsStripVisible(), /* needsInputViewShown */ false); 783c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka // Delay updating suggestions because keyboard input view may not be shown at this point. 784c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka mHandler.postUpdateSuggestions(); 785ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 786c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 787240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn, 788240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard mSettingsValues.mKeyPreviewPopupDismissDelay); 789c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka inputView.setProximityCorrectionEnabled(true); 790c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 791055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka voiceIme.onStartInputView(inputView.getWindowToken()); 792c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 793c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); 794c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka } 795c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka 796923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 797e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka public void onWindowHidden() { 798e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka super.onWindowHidden(); 799f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 800e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka if (inputView != null) inputView.closing(); 801e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 802e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 80359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputInternal() { 804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onFinishInput(); 805a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 806979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 807979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 808b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging); 809409220583333bdf06290dd9fd42f91b5c0d1b11asatok 810f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 811d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa if (inputView != null) inputView.closing(); 812f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard if (mUserUnigramDictionary != null) mUserUnigramDictionary.flushPendingWrites(); 813979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites(); 814466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 815466741d8a78965b8509bf527344f289e50873092Mike LeBeau 81659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka private void onFinishInputViewInternal(boolean finishingInput) { 8176495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa super.onFinishInputView(finishingInput); 818055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardSwitcher.onFinishInputView(); 819f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 8205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (inputView != null) inputView.cancelAllMessages(); 821d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka // Remove pending messages related to update suggestions 822d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.cancelUpdateSuggestions(); 8236495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa } 8246495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa 8256495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa @Override 826466741d8a78965b8509bf527344f289e50873092Mike LeBeau public void onUpdateExtractedText(int token, ExtractedText text) { 827466741d8a78965b8509bf527344f289e50873092Mike LeBeau super.onUpdateExtractedText(token, text); 828b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.showPunctuationHintIfNecessary(); 829923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 831923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 832923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onUpdateSelection(int oldSelStart, int oldSelEnd, 833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int newSelStart, int newSelEnd, 834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project int candidatesStart, int candidatesEnd) { 835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, 836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project candidatesStart, candidatesEnd); 837466741d8a78965b8509bf527344f289e50873092Mike LeBeau 838466741d8a78965b8509bf527344f289e50873092Mike LeBeau if (DEBUG) { 839466741d8a78965b8509bf527344f289e50873092Mike LeBeau Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart 840466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ose=" + oldSelEnd 841025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lss=" + mLastSelectionStart 842025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa + ", lse=" + mLastSelectionEnd 843466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nss=" + newSelStart 844466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", nse=" + newSelEnd 845466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", cs=" + candidatesStart 846466741d8a78965b8509bf527344f289e50873092Mike LeBeau + ", ce=" + candidatesEnd); 847466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 848466741d8a78965b8509bf527344f289e50873092Mike LeBeau 849b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart); 8504f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett 851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // If the current selection in the text view changes, we should 852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // clear whatever candidate text we have. 853025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa final boolean selectionChanged = (newSelStart != candidatesEnd 854025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart; 855025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1; 8564733609947c0ec74e460bd714fffca0518ade93aJean Chalard if (!mExpectingUpdateSelection) { 857cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // TAKE CARE: there is a race condition when we enter this test even when the user 858cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // did not explicitly move the cursor. This happens when typing fast, where two keys 859cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // turn this flag on in succession and both onUpdateSelection() calls arrive after 860cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // the second one - the first call successfully avoids this test, but the second one 861cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard // enters. For the moment we rely on candidatesCleared to further reduce the impact. 862120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (SPACE_STATE_WEAK == mSpaceState) { 863120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Test for no WEAK_SPACE action because there is a race condition that may end up 864120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // in coming here on a normal key press. We set this to NONE because after 865120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // a cursor move, we don't want the suggestion strip to swap the space with the 866120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // newly inserted punctuation. 867120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 868126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 869196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (((mWordComposer.isComposingWord()) 8704c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard || mVoiceProxy.isVoiceInputHighlighted()) 8714c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard && (selectionChanged || candidatesCleared)) { 8723651220327c051d8017045aa5e8919461507b3f8Jean Chalard mWordComposer.reset(); 873cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard updateSuggestions(); 8744c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard final InputConnection ic = getCurrentInputConnection(); 8754c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard if (ic != null) { 8764c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard ic.finishComposingText(); 8774c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 878604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.onFinishComposingText(); 8794c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard mVoiceProxy.setVoiceInputHighlighted(false); 880196d82cdd740580ed79d801483dbc282be85d076Jean Chalard } else if (!mWordComposer.isComposingWord()) { 881cd2286fff1ce0aaa5e3f60e55afba2299101207cJean Chalard mWordComposer.reset(); 882cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard updateSuggestions(); 8834c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard } 8844733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 8854733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = false; 886d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateShiftKeyState(); 8876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not 8886b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // here. It would probably be too expensive to call directly here but we may want to post a 8896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // message to delay it. The point would be to unify behavior between backspace to the 8906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // end of a word and manually put the pointer at the end of the word. 891466741d8a78965b8509bf527344f289e50873092Mike LeBeau 892979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Make a note of the cursor position 893979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionStart = newSelStart; 894979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mLastSelectionEnd = newSelEnd; 8957a8dac55278cedd838be325f56b4c52d973c61f5satok } 8967a8dac55278cedd838be325f56b4c52d973c61f5satok 897c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 898c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has clicked on the extracted text view, 899c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * when running in fullscreen mode. The default implementation hides 900913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * the suggestions view when this happens, but only if the extracted text 901c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * editor has a vertical scroll bar because its text doesn't fit. 902c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 903913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 904c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 905c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 906c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedTextClicked() { 907fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard if (isSuggestionsRequested()) return; 908c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 909c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedTextClicked(); 910c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 911c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 912c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani /** 913c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * This is called when the user has performed a cursor movement in the 914c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * extracted text view, when it is running in fullscreen mode. The default 915913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * implementation hides the suggestions view when a vertical movement 916c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * happens, but only if the extracted text editor has a vertical scroll bar 917c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * because its text doesn't fit. 918c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani * Here we override the behavior due to the possibility that a re-correction could 919913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * cause the suggestions strip to disappear and re-appear. 920c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani */ 921c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani @Override 922c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani public void onExtractedCursorMovement(int dx, int dy) { 923fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard if (isSuggestionsRequested()) return; 924c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 925c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani super.onExtractedCursorMovement(dx, dy); 926c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani } 927c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani 928923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 929923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void hideWindow() { 930979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.commit(); 931c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mKeyboardSwitcher.onHideWindow(); 932979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 933923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (TRACE) Debug.stopMethodTracing(); 9346e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani if (mOptionsDialog != null && mOptionsDialog.isShowing()) { 9356e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog.dismiss(); 9366e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani mOptionsDialog = null; 9376e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 938b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.hideVoiceWindow(mConfigurationChanging); 939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.hideWindow(); 940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 9431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) { 944979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (DEBUG) { 945a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa Log.i(TAG, "Received completions:"); 946bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok if (applicationSpecifiedCompletions != null) { 947bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 948bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]); 949bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok } 950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 952dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn) { 9531b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka mApplicationSpecifiedCompletions = applicationSpecifiedCompletions; 9541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka if (applicationSpecifiedCompletions == null) { 955b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani clearSuggestions(); 956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 958a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 9597e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka SuggestedWords.Builder builder = new SuggestedWords.Builder() 9601b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions) 9615238df54ad3f648d09d5288f00b0a9d3c0593832Tadashi G. Takaoka .setTypedWordValid(false) 9625238df54ad3f648d09d5288f00b0a9d3c0593832Tadashi G. Takaoka .setHasMinimalSuggestion(false); 963979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // When in fullscreen mode, show completions generated by the application 9647e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(builder.build()); 965117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mWordComposer.deleteAutoCorrection(); 966c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShown(true); 967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 970c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { 971913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // TODO: Modify this if we support suggestions with hard keyboard 972913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { 973913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean shouldShowSuggestions = shown 9747a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true); 9754b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka if (isFullscreenMode()) { 976913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 977913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.GONE); 9787a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } else { 979913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsContainer.setVisibility( 980913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); 9817a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka } 982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 984a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 985c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private void setSuggestionStripShown(boolean shown) { 986c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka setSuggestionStripShownInternal(shown, /* needsInputViewShown */true); 987543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa } 988543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa 989543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa @Override 990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onComputeInsets(InputMethodService.Insets outInsets) { 991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.onComputeInsets(outInsets); 992f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 993913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (inputView == null || mSuggestionsContainer == null) 99446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka return; 995d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // In fullscreen mode, the height of the extract area managed by InputMethodService should 996d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // be considered. 997d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}. 998d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0; 999abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka final int backingHeight = (mKeyPreviewBackingView.getVisibility() == View.GONE) ? 0 1000abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka : mKeyPreviewBackingView.getHeight(); 100159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0 100259010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka : mSuggestionsContainer.getHeight(); 1003d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka final int extraHeight = extractHeight + backingHeight + suggestionsHeight; 1004abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka int touchY = extraHeight; 10059e347d3d448e48229c46aad394ec9bd60cd5807bsatok // Need to set touchable region only if input view is being shown 100646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka if (mKeyboardSwitcher.isInputViewShown()) { 1007913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { 100859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka touchY -= suggestionsHeight; 10099e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 10107a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka final int touchWidth = inputView.getWidth(); 1011abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka final int touchHeight = inputView.getHeight() + extraHeight 10127a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka // Extend touchable region below the keyboard. 10137a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + EXTENDED_TOUCHABLE_REGION_HEIGHT; 10149e347d3d448e48229c46aad394ec9bd60cd5807bsatok if (DEBUG) { 10157a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth 10167a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka + " height=" + touchHeight); 10179e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 10187a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight); 10199e347d3d448e48229c46aad394ec9bd60cd5807bsatok } 102046ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.contentTopInsets = touchY; 102146ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka outInsets.visibleTopInsets = touchY; 1022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1023a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 1025979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public boolean onEvaluateFullscreenMode() { 10269751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka // Reread resource value here, because this method is called by framework anytime as needed. 10279751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka final boolean isFullscreenModeAllowed = 10289751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka mSettingsValues.isFullscreenModeAllowed(getResources()); 10299751a626ec9b2e771afa5b3757e8f8498a328683Tadashi G. Takaoka return super.onEvaluateFullscreenMode() && isFullscreenModeAllowed; 103059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka } 103159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka 103259010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka @Override 103359010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka public void updateFullscreenMode() { 103459010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka super.updateFullscreenMode(); 1035f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka 103659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka if (mKeyPreviewBackingView == null) return; 1037549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka // In fullscreen mode, no need to have extra space to show the key preview. 103859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka // If not, we should have extra space above the keyboard to show the key preview. 1039549e295dc113bff50077c3c355dcd94af09a1b2fTadashi G. Takaoka mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE); 1040979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1041979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1042979f8690967ff5409fe18f5085858ccdb8e0ccf1satok @Override 1043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) { 1044923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (keyCode) { 1045e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_BACK: 10462cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka if (event.getRepeatCount() == 0) { 10472cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka if (mSuggestionsView != null && mSuggestionsView.handleBack()) { 10482cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka return true; 10492cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka } 10502cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView(); 10512cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka if (keyboardView != null && keyboardView.handleBack()) { 10526e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani return true; 10536e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani } 1054e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 1055e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka break; 1056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return super.onKeyDown(keyCode, event); 1058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1060923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 1061923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean onKeyUp(int keyCode, KeyEvent event) { 1062923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (keyCode) { 1063e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_DOWN: 1064e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_UP: 1065e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_LEFT: 1066e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka case KeyEvent.KEYCODE_DPAD_RIGHT: 1067e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka // Enable shift key and DPAD to do selections 1068e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka if (mKeyboardSwitcher.isInputViewShown() 1069e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka && mKeyboardSwitcher.isShiftedOrShiftLocked()) { 1070e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(), 1071e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka event.getAction(), event.getKeyCode(), event.getRepeatCount(), 1072e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka event.getDeviceId(), event.getScanCode(), 1073e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON); 10749351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1075e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka if (ic != null) 1076e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ic.sendKeyEvent(newEvent); 1077e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka return true; 1078e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 1079e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka break; 1080923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1081923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return super.onKeyUp(keyCode, event); 1082923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1083923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 10849351550dc6af7859e5280e16144c9386a37b976dKen Wakasa public void commitTyped(final InputConnection ic) { 1085196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) return; 10863651220327c051d8017045aa5e8919461507b3f8Jean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 10870fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_USER_TYPED_WORD); 10883651220327c051d8017045aa5e8919461507b3f8Jean Chalard if (typedWord.length() > 0) { 10899351550dc6af7859e5280e16144c9386a37b976dKen Wakasa if (ic != null) { 10903651220327c051d8017045aa5e8919461507b3f8Jean Chalard ic.commitText(typedWord, 1); 1091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 10923651220327c051d8017045aa5e8919461507b3f8Jean Chalard addToUserUnigramAndBigramDictionaries(typedWord, 1093f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard UserUnigramDictionary.FREQUENCY_FOR_TYPED); 1094923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 10958558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa updateSuggestions(); 1096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1098b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public boolean getCurrentAutoCapsState() { 10999351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 11001c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani EditorInfo ei = getCurrentInputEditorInfo(); 110117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSettingsValues.mAutoCap && ic != null && ei != null 110217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard && ei.inputType != InputType.TYPE_NULL) { 1103b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return ic.getCursorCapsMode(ei.inputType) != 0; 11041c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 1105b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 11061c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 11071c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani 1108b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard // "ic" may be null 1109b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard private void swapSwapperAndSpaceWhileInBatchEdit(final InputConnection ic) { 1110b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard if (null == ic) return; 1111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project CharSequence lastTwo = ic.getTextBeforeCursor(2, 0); 1112863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called. 1113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastTwo != null && lastTwo.length() == 2 1114863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard && lastTwo.charAt(0) == Keyboard.CODE_SPACE) { 1115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.deleteSurroundingText(2, 0); 1116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.commitText(lastTwo.charAt(1) + " ", 1); 1117b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 11184ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 11194ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa } 11204ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1121120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private boolean maybeDoubleSpaceWhileInBatchEdit(final InputConnection ic) { 1122120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (mCorrectionMode == Suggest.CORRECTION_NONE) return false; 1123120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (ic == null) return false; 11242b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); 1125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (lastThree != null && lastThree.length() == 3 11269351550dc6af7859e5280e16144c9386a37b976dKen Wakasa && Utils.canBeFollowedByPeriod(lastThree.charAt(0)) 1127571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastThree.charAt(1) == Keyboard.CODE_SPACE 1128fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka && lastThree.charAt(2) == Keyboard.CODE_SPACE 1129fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka && mHandler.isAcceptingDoubleSpaces()) { 1130fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka mHandler.cancelDoubleSpacesTimer(); 1131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.deleteSurroundingText(2, 0); 1132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.commitText(". ", 1); 1133b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 1134120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 1135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1136120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return false; 1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1138a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1139b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard // "ic" must not be null 11408fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { 114141a519729505a877844f2c57a33509c302dddbceKen Wakasa // When the text's first character is '.', remove the previous period 114241a519729505a877844f2c57a33509c302dddbceKen Wakasa // if there is one. 1143b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); 11444ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa if (lastOne != null && lastOne.length() == 1 1145571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastOne.charAt(0) == Keyboard.CODE_PERIOD 1146571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && text.charAt(0) == Keyboard.CODE_PERIOD) { 114741a519729505a877844f2c57a33509c302dddbceKen Wakasa ic.deleteSurroundingText(1, 0); 114841a519729505a877844f2c57a33509c302dddbceKen Wakasa } 114941a519729505a877844f2c57a33509c302dddbceKen Wakasa } 115041a519729505a877844f2c57a33509c302dddbceKen Wakasa 1151b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard // "ic" may be null 11528fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { 11539a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic == null) return; 1154b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); 11559a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (lastOne != null && lastOne.length() == 1 1156571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka && lastOne.charAt(0) == Keyboard.CODE_SPACE) { 11579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa ic.deleteSurroundingText(1, 0); 11589a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 11599a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 11609a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa 1161c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 1162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean addWordToDictionary(String word) { 1163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mUserDictionary.addWord(word, 128); 11646558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // Suggestion strip should be updated after the operation of adding word to the 11656558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // user dictionary 1166d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 1168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 11708fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean isAlphabet(int code) { 11718fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka return Character.isLetter(code); 1172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1173a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1174e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka private void onSettingsKeyPressed() { 1175cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return; 1176d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { 1177d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka showSubtypeSelectorAndSettings(); 117823d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(false /* exclude aux subtypes */)) { 1179d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka showOptionsMenu(); 1180d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka } else { 1181d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka launchSettings(); 11829a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11839a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 11849a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1185cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa // Virtual codes representing custom requests. These are used in onCustomRequest() below. 1186cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; 1187d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka public static final int CODE_HAPTIC_AND_AUDIO_FEEDBACK = 2; 1188cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa 1189cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa @Override 1190cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa public boolean onCustomRequest(int requestCode) { 1191cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa if (isShowingOptionDialog()) return false; 1192cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa switch (requestCode) { 1193cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa case CODE_SHOW_INPUT_METHOD_PICKER: 119423d27fefcbfe04df8f8762d5d50117a58fb011e9Tadashi G. Takaoka if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { 119579efbed76f638be298493107fa2d0cd1b5eb529esatok mImm.showInputMethodPicker(); 1196cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return true; 11979a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1198cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 1199d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka case CODE_HAPTIC_AND_AUDIO_FEEDBACK: 1200d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka hapticAndAudioFeedback(Keyboard.CODE_UNSPECIFIED); 1201d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka return true; 12029a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 1203cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa return false; 12049a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 12059a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 12069a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok private boolean isShowingOptionDialog() { 12079a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok return mOptionsDialog != null && mOptionsDialog.isShowing(); 12089a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok } 12099a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok 1210120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void insertPunctuationFromSuggestionStrip(final InputConnection ic, final int code) { 1211120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : null; 1212120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int toLeft = TextUtils.isEmpty(beforeText) ? 0 : beforeText.charAt(0); 1213120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final boolean shouldRegisterSwapPunctuation; 1214120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // If we have a space left of the cursor and it's a weak or a magic space, then we should 1215120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // swap it, and override the space state with SPACESTATE_SWAP_PUNCTUATION. 1216120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // To swap it, we fool handleSeparator to think the previous space state was a 1217120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // magic space. 12189de5cfc67a4e349c547e40678add27cdd6ca8490Jean Chalard if (Keyboard.CODE_SPACE == toLeft && mSpaceState == SPACE_STATE_WEAK 1219a8c8ab1cb4f148693ebf8443c62b029db0840d26Jean Chalard && mSettingsValues.isMagicSpaceSwapper(code)) { 1220120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_MAGIC; 1221120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard shouldRegisterSwapPunctuation = true; 1222120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else { 1223120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard shouldRegisterSwapPunctuation = false; 1224120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1225120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard onCodeInput(code, new int[] { code }, 1226120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard KeyboardActionListener.NOT_A_TOUCH_COORDINATE, 1227120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard KeyboardActionListener.NOT_A_TOUCH_COORDINATE); 1228120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (shouldRegisterSwapPunctuation) { 1229120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_SWAP_PUNCTUATION; 1230120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1231126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 1232126698fdd256a2e3734634d3b923cabd800064baJean Chalard 12335f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Implementation of {@link KeyboardActionListener}. 12345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 12358aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) { 1236175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final long when = SystemClock.uptimeMillis(); 1237571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) { 1238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mDeleteCount = 0; 1239923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mLastKeyTime = when; 1241175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1242b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); 1243120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // The space state depends only on the last character pressed and its own previous 1244120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // state. Here, we revert the space state to neutral if the key is actually modifying 1245120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // the input contents (any non-shift key), which is what we should do for 1246120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // all inputs that do not result in a special state. Each character handling is then 1247120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // free to override the state as they see fit. 1248120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState = mSpaceState; 1249ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1250ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa // TODO: Consolidate the double space timer, mLastKeyTime, and the space state. 1251ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa if (primaryCode != Keyboard.CODE_SPACE) { 1252ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa mHandler.cancelDoubleSpacesTimer(); 1253ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa } 1254ed631627cb2337b025f0e80df6fecf1e6e511dc4Ken Wakasa 1255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 1256571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_DELETE: 1257120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1258120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleBackspace(spaceState); 12594189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka mDeleteCount++; 12604733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 12614189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka LatinImeLogger.logOnDelete(); 12624189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1263571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_SHIFT: 12644189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka // Shift key is handled in onPress() when device has distinct multi-touch panel. 12655619d7658459d13723b6d7ad8969b249adf9e717Tadashi G. Takaoka if (!distinctMultiTouch) { 1266b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka switcher.toggleShift(); 12675619d7658459d13723b6d7ad8969b249adf9e717Tadashi G. Takaoka } 12684189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1269e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: 12704189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka // Symbol key is handled in onPress() when device has distinct multi-touch panel. 12715619d7658459d13723b6d7ad8969b249adf9e717Tadashi G. Takaoka if (!distinctMultiTouch) { 127296c56cb577ff6b76e2c182f45402842e828c3644Tadashi G. Takaoka switcher.toggleAlphabetAndSymbols(); 12735619d7658459d13723b6d7ad8969b249adf9e717Tadashi G. Takaoka } 12744189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1275e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka case Keyboard.CODE_SETTINGS: 127693246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka onSettingsKeyPressed(); 12774189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1278571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_CAPSLOCK: 1279b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka switcher.toggleCapsLock(); 1280d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka hapticAndAudioFeedback(primaryCode); 12814189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1282d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka case Keyboard.CODE_SHORTCUT: 128393246652638f423d5220449f65495dea0639c750Tadashi G. Takaoka mSubtypeSwitcher.switchToShortcutIME(); 12844189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 1285571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka case Keyboard.CODE_TAB: 128645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka handleTab(); 12874733609947c0ec74e460bd714fffca0518ade93aJean Chalard // There are two cases for tab. Either we send a "next" event, that may change the 12884733609947c0ec74e460bd714fffca0518ade93aJean Chalard // focus but will never move the cursor. Or, we send a real tab keycode, which some 12894733609947c0ec74e460bd714fffca0518ade93aJean Chalard // applications may accept or ignore, and we don't know whether this will move the 12904733609947c0ec74e460bd714fffca0518ade93aJean Chalard // cursor or not. So actually, we don't really know. 12914733609947c0ec74e460bd714fffca0518ade93aJean Chalard // So to go with the safer option, we'd rather behave as if the user moved the 12924733609947c0ec74e460bd714fffca0518ade93aJean Chalard // cursor when they didn't than the opposite. We also expect that most applications 12934733609947c0ec74e460bd714fffca0518ade93aJean Chalard // will actually use tab only for focus movement. 12944733609947c0ec74e460bd714fffca0518ade93aJean Chalard // To sum it up: do not update mExpectingUpdateSelection here. 12954189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka break; 12964189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka default: 1297120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 129817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSettingsValues.isWordSeparator(primaryCode)) { 1299120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleSeparator(primaryCode, x, y, spaceState); 13004189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 1301120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard handleCharacter(primaryCode, keyCodes, x, y, spaceState); 13024189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 13034733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 13044733609947c0ec74e460bd714fffca0518ade93aJean Chalard break; 1305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1306eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka switcher.onCodeInput(primaryCode); 1307dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani // Reset after any single keystroke 1308dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = null; 1309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1310a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 13115a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13128aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onTextInput(CharSequence text) { 1313b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.commitVoiceInput(); 13149351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic == null) return; 1316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.beginBatchEdit(); 131755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka commitTyped(ic); 13189351550dc6af7859e5280e16144c9386a37b976dKen Wakasa maybeRemovePreviousPeriod(ic, text); 1319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.commitText(text, 1); 1320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.endBatchEdit(); 1321b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 13228cab0b56eb8db311f158b18a361d9ceb85cff482Tadashi G. Takaoka mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); 1323120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_NONE; 1324dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani mEnteredText = text; 13259e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard mWordComposer.reset(); 1326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 13285a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 13298aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() { 133083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka // User released a finger outside any key 13315f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka mKeyboardSwitcher.onCancelInput(); 133283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } 133383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka 1334120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleBackspace(final int spaceState) { 1335b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok if (mVoiceProxy.logAndRevertVoiceInput()) return; 1336504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 1337504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka if (ic == null) return; 1338979f8690967ff5409fe18f5085858ccdb8e0ccf1satok ic.beginBatchEdit(); 1339a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard handleBackspaceWhileInBatchEdit(spaceState, ic); 1340a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard ic.endBatchEdit(); 1341a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard } 1342979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1343a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard // "ic" may not be null. 1344a2a85d45e0618dc0dd7d224d5a0e7394d9003dc5Jean Chalard private void handleBackspaceWhileInBatchEdit(final int spaceState, final InputConnection ic) { 1345b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.handleBackspace(); 13464f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett 13472245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard // In many cases, we may have to put the keyboard in auto-shift state again. 13482245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard mHandler.postUpdateShiftKeyState(); 13492245c3b5b3691928b08fd6accf8d4a21fb35e26bJean Chalard 13505c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { 13515c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // Cancel multi-character input: remove the text we just entered. 13525c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // This is triggered on backspace after a key that inputs multiple characters, 13535c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // like the smiley key or the .com key. 13545c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard ic.deleteSurroundingText(mEnteredText.length(), 0); 13555c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // If we have mEnteredText, then we know that mHasUncommittedTypedChars == false. 13565c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // In addition we know that spaceState is false, and that we should not be 13575c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard // reverting any autocorrect at this point. So we can safely return. 13585c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard return; 13595c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard } 13605c3ff4c9c86e073d994ad874abe9dae7a665d5c4Jean Chalard 1361196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 13623651220327c051d8017045aa5e8919461507b3f8Jean Chalard final int length = mWordComposer.size(); 1363923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (length > 0) { 13649318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.deleteLast(); 136577d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1366196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // If we have deleted the last remaining character of a word, then we are not 1367196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // isComposingWord() any more. 1368196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) { 1369196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // Not composing word any more, so we can show bigrams. 1370cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.postUpdateBigramPredictions(); 137189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1372196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // Still composing a word, so we still have letters to deduce a suggestion from. 137389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard mHandler.postUpdateSuggestions(); 137489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 1375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.deleteSurroundingText(1, 0); 1377923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1378890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } else { 137972d285f4d758dd1ceafb7d9bd3dd330efd24c1f8Jean Chalard // We should be very careful about auto-correction cancellation and suggestion 138072d285f4d758dd1ceafb7d9bd3dd330efd24c1f8Jean Chalard // resuming here. The behavior needs to be different according to text field types, 138172d285f4d758dd1ceafb7d9bd3dd330efd24c1f8Jean Chalard // and it would be much clearer to test for them explicitly here rather than 138272d285f4d758dd1ceafb7d9bd3dd330efd24c1f8Jean Chalard // relying on implicit values like "whether the suggestion strip is displayed". 13839e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard if (mWordComposer.didAutoCorrectToAnotherWord()) { 1384d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard Utils.Stats.onAutoCorrectionCancellation(); 1385d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard cancelAutoCorrect(ic); 1386120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return; 1387120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1388d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard 1389d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (SPACE_STATE_DOUBLE == spaceState) { 1390d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (revertDoubleSpace(ic)) { 1391d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // No need to reset mSpaceState, it has already be done (that's why we 1392d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // receive it as a parameter) 1393d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1394d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 1395d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) { 1396d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard if (revertSwapPunctuation(ic)) { 1397d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard // Likewise 1398d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard return; 1399d2c69c7d1231c238afc9196dcb9cc2359de520cfJean Chalard } 14004733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 1401504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka 140272d285f4d758dd1ceafb7d9bd3dd330efd24c1f8Jean Chalard // See the comment above: must be careful about resuming auto-suggestion. 1403913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { 14046558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // Go back to the suggestion mode if the user canceled the 140555b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa // "Touch again to save". 1406a8ba49c2534220105ce302a50b3a9ddaf831ef20Jean Chalard // NOTE: In general, we don't revert the word when backspacing 14076558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // from a manual suggestion pick. We deliberately chose a 14086558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // different behavior only in the case of picking the first 14096558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // suggestion (typed word). It's intentional to have made this 14106558253160e2039c87f424bd814f402ecd31de3bKen Wakasa // inconsistent with backspacing after selecting other suggestions. 1411890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard restartSuggestionsOnManuallyPickedTypedWord(ic); 14126558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } else { 14136b1f500da451de56932a8b2a99c63857994ece85Jean Chalard ic.deleteSurroundingText(1, 0); 14146558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (mDeleteCount > DELETE_ACCELERATE_AT) { 14156b1f500da451de56932a8b2a99c63857994ece85Jean Chalard ic.deleteSurroundingText(1, 0); 14166558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 14176b1f500da451de56932a8b2a99c63857994ece85Jean Chalard restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic); 1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 142245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka private void handleTab() { 142345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final int imeOptions = getCurrentInputEditorInfo().imeOptions; 1424b2707856aba4fc9b063f26305f1fb603b19c1701satok if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) 1425b2707856aba4fc9b063f26305f1fb603b19c1701satok && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) { 142645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB); 142745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka return; 142845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } 142945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka 143045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 143145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (ic == null) 143245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka return; 143345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka 143445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // True if keyboard is in either chording shift or manual temporary upper case mode. 143545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase(); 1436b2707856aba4fc9b063f26305f1fb603b19c1701satok if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions) 143745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka && !isManualTemporaryUpperCase) { 1438b2707856aba4fc9b063f26305f1fb603b19c1701satok EditorInfoCompatUtils.performEditorActionNext(ic); 1439b2707856aba4fc9b063f26305f1fb603b19c1701satok } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions) 144045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka && isManualTemporaryUpperCase) { 1441b2707856aba4fc9b063f26305f1fb603b19c1701satok EditorInfoCompatUtils.performEditorActionPrevious(ic); 144245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } 144345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } 144445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka 1445120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x, 1446120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int y, final int spaceState) { 1447b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.handleCharacter(); 1448b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard final InputConnection ic = getCurrentInputConnection(); 1449dafa7a8e15447544842975047f831883e67700c5Jean Chalard if (null != ic) ic.beginBatchEdit(); 1450dafa7a8e15447544842975047f831883e67700c5Jean Chalard // TODO: if ic is null, does it make any sense to call this? 1451dafa7a8e15447544842975047f831883e67700c5Jean Chalard handleCharacterWhileInBatchEdit(primaryCode, keyCodes, x, y, spaceState, ic); 1452dafa7a8e15447544842975047f831883e67700c5Jean Chalard if (null != ic) ic.endBatchEdit(); 1453dafa7a8e15447544842975047f831883e67700c5Jean Chalard } 1454dafa7a8e15447544842975047f831883e67700c5Jean Chalard 1455dafa7a8e15447544842975047f831883e67700c5Jean Chalard // "ic" may be null without this crashing, but the behavior will be really strange 1456dafa7a8e15447544842975047f831883e67700c5Jean Chalard private void handleCharacterWhileInBatchEdit(final int primaryCode, final int[] keyCodes, 1457dafa7a8e15447544842975047f831883e67700c5Jean Chalard final int x, final int y, final int spaceState, final InputConnection ic) { 1458120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (SPACE_STATE_MAGIC == spaceState 1459126698fdd256a2e3734634d3b923cabd800064baJean Chalard && mSettingsValues.isMagicSpaceStripper(primaryCode)) { 1460dafa7a8e15447544842975047f831883e67700c5Jean Chalard if (null != ic) removeTrailingSpaceWhileInBatchEdit(ic); 14610730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard } 14620730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard 1463196d82cdd740580ed79d801483dbc282be85d076Jean Chalard boolean isComposingWord = mWordComposer.isComposingWord(); 1464e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka int code = primaryCode; 14653889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code)) 14663889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa && isSuggestionsRequested() && !isCursorTouchingWord()) { 14677b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (!isComposingWord) { 14686d1cbbc2ffb9d7046189174ec68b5b72bbc154b3Jean Chalard // Reset entirely the composing state anyway, then start composing a new word unless 14697b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard // the character is a single quote. The idea here is, single quote is not a 14707b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard // separator and it should be treated as a normal character, except in the first 14717b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard // position where it should not start composing a word. 14727b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != code); 14739318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.reset(); 14747e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa clearSuggestions(); 1475604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.onFinishComposingText(); 1476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 147835f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 1479f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (switcher.isShiftedOrShiftLocked()) { 1480eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT 1481eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani || keyCodes[0] > Character.MAX_CODE_POINT) { 1482eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani return; 1483eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani } 1484e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka code = keyCodes[0]; 1485e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka if (switcher.isAlphabetMode() && Character.isLowerCase(code)) { 148635f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka // In some locales, such as Turkish, Character.toUpperCase() may return a wrong 148735f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka // character because it doesn't take care of locale. 148835f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka final String upperCaseString = new String(new int[] {code}, 0, 1) 148935f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka .toUpperCase(mSubtypeSwitcher.getInputLocale()); 149035f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) { 149135f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka code = upperCaseString.codePointAt(0); 149212a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka } else { 149312a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka // Some keys, such as [eszett], have upper case as multi-characters. 149435f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka onTextInput(upperCaseString); 149512a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka return; 149612a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka } 1497979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1498923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 14997b5bc1ff4d4694045e69e6aff8a2b5365ff882d1Jean Chalard if (isComposingWord) { 15009318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.add(code, keyCodes, x, y); 1501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 15021c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani // If it's the first letter, make note of auto-caps state 15039318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa if (mWordComposer.size() == 1) { 15049318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa mWordComposer.setAutoCapitalized(getCurrentAutoCapsState()); 1505604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.onStartComposingText(); 15061c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani } 150777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ic.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1); 1508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1509d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1510923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1511e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka sendKeyChar((char)code); 1512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1513120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (SPACE_STATE_MAGIC == spaceState 1514126698fdd256a2e3734634d3b923cabd800064baJean Chalard && mSettingsValues.isMagicSpaceSwapper(primaryCode)) { 1515b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard if (null != ic) swapSwapperAndSpaceWhileInBatchEdit(ic); 1516863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard } 1517863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 1518406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard if (mSettingsValues.isWordSeparator(code)) { 1519406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)code, x, y); 1520406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard } else { 1521406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onNonSeparator((char)code, x, y); 1522406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard } 1523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1525120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard private void handleSeparator(final int primaryCode, final int x, final int y, 1526120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final int spaceState) { 1527b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.handleSeparator(); 1528604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.onFinishComposingText(); 15294f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett 153055b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa // Should dismiss the "Touch again to save" message when handling separator 1531913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { 1532cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.cancelUpdateBigramPredictions(); 1533d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 15346558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 15356558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 1536923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Handle separator 15371b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka final InputConnection ic = getCurrentInputConnection(); 1538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.beginBatchEdit(); 1540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1541196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (mWordComposer.isComposingWord()) { 1542923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // In certain languages where single quote is a separator, it's better 1543a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker // not to auto correct, but accept the typed word. For instance, 1544923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // in Italian dov' should not be expanded to dove' because the elision 1545923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // requires the last vowel to be removed. 1546f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled 1547dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && !mInputAttributes.mInputTypeNoAutoCorrect; 154817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { 1549f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard commitCurrentAutoCorrection(primaryCode, ic); 1550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project commitTyped(ic); 1552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 15544ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa 1555120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final boolean swapMagicSpace; 15562c77216e22e5f9d1d2191ce577f2707bea5b815aJean Chalard if (Keyboard.CODE_ENTER == primaryCode && (SPACE_STATE_MAGIC == spaceState 15572c77216e22e5f9d1d2191ce577f2707bea5b815aJean Chalard || SPACE_STATE_SWAP_PUNCTUATION == spaceState)) { 15582c77216e22e5f9d1d2191ce577f2707bea5b815aJean Chalard removeTrailingSpaceWhileInBatchEdit(ic); 15592c77216e22e5f9d1d2191ce577f2707bea5b815aJean Chalard swapMagicSpace = false; 15602c77216e22e5f9d1d2191ce577f2707bea5b815aJean Chalard } else if (SPACE_STATE_MAGIC == spaceState) { 156117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) { 1562120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard swapMagicSpace = true; 1563863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard } else { 1564120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard swapMagicSpace = false; 1565b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard if (mSettingsValues.isMagicSpaceStripper(primaryCode)) { 1566b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard removeTrailingSpaceWhileInBatchEdit(ic); 1567b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard } 1568863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard } 15690730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard } else { 1570120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard swapMagicSpace = false; 1571863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard } 1572863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard 1573120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard sendKeyChar((char)primaryCode); 157489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 157589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (Keyboard.CODE_SPACE == primaryCode) { 1576120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (isSuggestionsRequested()) { 1577120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (maybeDoubleSpaceWhileInBatchEdit(ic)) { 1578120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_DOUBLE; 1579120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } else if (!isShowingPunctuationList()) { 1580120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_WEAK; 1581120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1582126698fdd256a2e3734634d3b923cabd800064baJean Chalard } 1583120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1584120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mHandler.startDoubleSpacesTimer(); 158589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (!isCursorTouchingWord()) { 158689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard mHandler.cancelUpdateSuggestions(); 1587cb3320179d39a7983874697a0aa428b127675c9dJean Chalard mHandler.postUpdateBigramPredictions(); 158889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 158989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 1590120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard if (swapMagicSpace) { 1591120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard swapSwapperAndSpaceWhileInBatchEdit(ic); 1592120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_MAGIC; 1593120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 1594120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 159589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Set punctuation right away. onUpdateSelection will fire but tests whether it is 159689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // already displayed or not, so it's okay. 159755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka setPunctuationSuggestions(); 1598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1599120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1600406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)primaryCode, x, y); 1601120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 1602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 1603923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project ic.endBatchEdit(); 1604923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1606466741d8a78965b8509bf527344f289e50873092Mike LeBeau 160777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard private CharSequence getTextWithUnderline(final CharSequence text) { 160877d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard return mComposingStateManager.isAutoCorrectionIndicatorOn() 160977d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) 161077d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard : mWordComposer.getTypedWord(); 161177d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 161277d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard 1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void handleClose() { 1614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project commitTyped(getCurrentInputConnection()); 1615b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok mVoiceProxy.handleClose(); 1616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestHideSelf(0); 1617c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 16181679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka if (inputView != null) 16191679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka inputView.closing(); 1620923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 16227a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isSuggestionsRequested() { 1623dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard return mInputAttributes.mIsSettingsSuggestionStripOn 1624c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka && (mCorrectionMode > 0 || isShowingSuggestionsStrip()); 1625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1626a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 16277a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isShowingPunctuationList() { 1628cb8cb95d0afd340de9f1a0e15948f0068d2450bcKen Wakasa if (mSuggestionsView == null) return false; 1629913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mSettingsValues.mSuggestPuncList == mSuggestionsView.getSuggestions(); 16307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 16327a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isShowingSuggestionsStrip() { 16337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE) 16347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE 163538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT); 16367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 16377599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 1638913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public boolean isSuggestionsStripVisible() { 1639913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView == null) 1640b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa return false; 1641d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard if (mSuggestionsView.isShowingAddToDictionaryHint()) 16429fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16439fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (!isShowingSuggestionsStrip()) 16449fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return false; 1645dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn) 16469fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return true; 16479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka return isSuggestionsRequested(); 1648923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1649923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1650409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void switchToKeyboardView() { 1651060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (DEBUG) { 1652060efb6d82af1f896d90cb845c8ae07c726f85e1satok Log.d(TAG, "Switch to keyboard view."); 1653060efb6d82af1f896d90cb845c8ae07c726f85e1satok } 1654c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka View v = mKeyboardSwitcher.getKeyboardView(); 1655060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (v != null) { 1656060efb6d82af1f896d90cb845c8ae07c726f85e1satok // Confirms that the keyboard view doesn't have parent view. 1657060efb6d82af1f896d90cb845c8ae07c726f85e1satok ViewParent p = v.getParent(); 1658060efb6d82af1f896d90cb845c8ae07c726f85e1satok if (p != null && p instanceof ViewGroup) { 1659060efb6d82af1f896d90cb845c8ae07c726f85e1satok ((ViewGroup) p).removeView(v); 16605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka } 1661060efb6d82af1f896d90cb845c8ae07c726f85e1satok setInputView(v); 1662060efb6d82af1f896d90cb845c8ae07c726f85e1satok } 1663913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1664060efb6d82af1f896d90cb845c8ae07c726f85e1satok updateInputViewShown(); 1665060efb6d82af1f896d90cb845c8ae07c726f85e1satok mHandler.postUpdateSuggestions(); 1666466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1667466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1668409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void clearSuggestions() { 16697e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(SuggestedWords.EMPTY); 1670466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1671466741d8a78965b8509bf527344f289e50873092Mike LeBeau 16727e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords words) { 1673913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) { 1674913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.setSuggestions(words); 16755e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka mKeyboardSwitcher.onAutoCorrectionStateChanged( 16765e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka words.hasWordAboveAutoCorrectionScoreThreshold()); 1677466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1678ec780e2868962bf17f0dfd35d36895f543bde40asatok 1679ec780e2868962bf17f0dfd35d36895f543bde40asatok // Put a blue underline to a word in TextView which will be auto-corrected. 1680ec780e2868962bf17f0dfd35d36895f543bde40asatok final InputConnection ic = getCurrentInputConnection(); 1681604d80c67185954d4691ac775be59c499eee3b1csatok if (ic != null) { 1682604d80c67185954d4691ac775be59c499eee3b1csatok final boolean oldAutoCorrectionIndicator = 1683604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.isAutoCorrectionIndicatorOn(); 1684604d80c67185954d4691ac775be59c499eee3b1csatok final boolean newAutoCorrectionIndicator = Utils.willAutoCorrect(words); 1685604d80c67185954d4691ac775be59c499eee3b1csatok if (oldAutoCorrectionIndicator != newAutoCorrectionIndicator) { 168677d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator); 168777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard if (DEBUG) { 1688fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok Log.d(TAG, "Flip the indicator. " + oldAutoCorrectionIndicator 1689fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok + " -> " + newAutoCorrectionIndicator); 169077d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard if (newAutoCorrectionIndicator 169177d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard != mComposingStateManager.isAutoCorrectionIndicatorOn()) { 169277d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard throw new RuntimeException("Couldn't flip the indicator! We are not " 169377d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard + "composing a word right now."); 169477d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard } 1695fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok } 169677d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard final CharSequence textWithUnderline = 169777d59b0691b8a9bd6cb336f07c175b88db53bbc0Jean Chalard getTextWithUnderline(mWordComposer.getTypedWord()); 1698604d80c67185954d4691ac775be59c499eee3b1csatok if (!TextUtils.isEmpty(textWithUnderline)) { 1699604d80c67185954d4691ac775be59c499eee3b1csatok ic.setComposingText(textWithUnderline, 1); 1700604d80c67185954d4691ac775be59c499eee3b1csatok } 1701ec780e2868962bf17f0dfd35d36895f543bde40asatok } 1702ec780e2868962bf17f0dfd35d36895f543bde40asatok } 1703466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 1704466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1705409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void updateSuggestions() { 1706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Check if we have a suggestion engine attached. 17079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if ((mSuggest == null || !isSuggestionsRequested()) 1708b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok && !mVoiceProxy.isVoiceInputHighlighted()) { 1709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1711466741d8a78965b8509bf527344f289e50873092Mike LeBeau 1712cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard mHandler.cancelUpdateSuggestions(); 1713cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard mHandler.cancelUpdateBigramPredictions(); 1714cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard 1715196d82cdd740580ed79d801483dbc282be85d076Jean Chalard if (!mWordComposer.isComposingWord()) { 1716ca26f20fa4903de46e374babbfba8c8a1a5cac93satok setPunctuationSuggestions(); 1717923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1718923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1719979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 17209f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok // TODO: May need a better way of retrieving previous word 172140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final InputConnection ic = getCurrentInputConnection(); 172240f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final CharSequence prevWord; 172340f7efc172928bdd6048e91421a766abe5b22996Jean Chalard if (null == ic) { 172440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard prevWord = null; 172540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard } else { 172640f7efc172928bdd6048e91421a766abe5b22996Jean Chalard prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); 172740f7efc172928bdd6048e91421a766abe5b22996Jean Chalard } 172840f7efc172928bdd6048e91421a766abe5b22996Jean Chalard // getSuggestedWordBuilder handles gracefully a null value of prevWord 1729f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(mWordComposer, 17303708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); 1731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1732dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard boolean autoCorrectionAvailable = !mInputAttributes.mInputTypeNoAutoCorrect 1733dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mSuggest.hasAutoCorrection(); 1734f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard final CharSequence typedWord = mWordComposer.getTypedWord(); 1735bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // Here, we want to promote a whitelisted word if exists. 17365f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid" 17375f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard // but still autocorrected from - in the case the whitelist only capitalizes the word. 17385f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard // The whitelist should be case-insensitive, so it's not possible to be consistent with 17395f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard // a boolean flag. Right now this is handled with a slight hack in 17405f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard // WhitelistDictionary#shouldForciblyAutoCorrectFrom. 1741f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard final int quotesCount = mWordComposer.trailingSingleQuotesCount(); 17425f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected( 1743c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard mSuggest.getUnigramDictionaries(), 1744c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard // If the typed string ends with a single quote, for dictionary lookup purposes 1745c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard // we behave as if the single quote was not here. Here, we are looking up the 1746c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard // typed string in the dictionary (to avoid autocorrecting from an existing 1747c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard // word, so for consistency this lookup should be made WITHOUT the trailing 1748c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard // single quote. 1749117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard quotesCount > 0 1750117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard ? typedWord.subSequence(0, typedWord.length() - quotesCount) : typedWord, 1751c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard preferCapitalization()); 1752979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (mCorrectionMode == Suggest.CORRECTION_FULL 1753979f8690967ff5409fe18f5085858ccdb8e0ccf1satok || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) { 17545f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard autoCorrectionAvailable |= (!allowsToBeAutoCorrected); 1755923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 17564a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani // Don't auto-correct words with multiple capital letter 1757f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard autoCorrectionAvailable &= !mWordComposer.isMostlyCaps(); 1758979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1759a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa // Basically, we update the suggestion strip only when suggestion count > 1. However, 1760a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa // there is an exception: We update the suggestion strip whenever typed word's length 1761f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // is 1 or typed word is found in dictionary, regardless of suggestion count. Actually, 1762f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // in most cases, suggestion count is 1 when typed word's length is 1, but we do always 1763f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // need to clear the previous state when the user starts typing a word (i.e. typed word's 1764f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka // length == 1). 1765fe1a6d961cf039357f061482461e4d2e951ad346satok if (typedWord != null) { 17665f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard if (builder.size() > 1 || typedWord.length() == 1 || (!allowsToBeAutoCorrected) 1767913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka || mSuggestionsView.isShowingAddToDictionaryHint()) { 17685f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard builder.setTypedWordValid(!allowsToBeAutoCorrected).setHasMinimalSuggestion( 17698558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa autoCorrectionAvailable); 1770fe1a6d961cf039357f061482461e4d2e951ad346satok } else { 1771074cda4d266b5d034d4348961c9183e32b16af5asatok SuggestedWords previousSuggestions = mSuggestionsView.getSuggestions(); 1772074cda4d266b5d034d4348961c9183e32b16af5asatok if (previousSuggestions == mSettingsValues.mSuggestPuncList) { 1773074cda4d266b5d034d4348961c9183e32b16af5asatok if (builder.size() == 0) { 1774074cda4d266b5d034d4348961c9183e32b16af5asatok return; 1775074cda4d266b5d034d4348961c9183e32b16af5asatok } 1776074cda4d266b5d034d4348961c9183e32b16af5asatok previousSuggestions = SuggestedWords.EMPTY; 1777074cda4d266b5d034d4348961c9183e32b16af5asatok } 1778fe1a6d961cf039357f061482461e4d2e951ad346satok builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); 1779fe1a6d961cf039357f061482461e4d2e951ad346satok } 17809fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka } 17817e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka showSuggestions(builder.build(), typedWord); 1782979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 17834a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani 17849fbfd5877305ed19a20663630b498b6b3fdae942satok public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { 17852aa1dd45c44295e2f7e8ece1b520032d86b9f908satok final boolean shouldBlockAutoCorrectionBySafetyNet = 17862aa1dd45c44295e2f7e8ece1b520032d86b9f908satok Utils.shouldBlockAutoCorrectionBySafetyNet(suggestedWords, mSuggest); 17872aa1dd45c44295e2f7e8ece1b520032d86b9f908satok if (shouldBlockAutoCorrectionBySafetyNet) { 17882aa1dd45c44295e2f7e8ece1b520032d86b9f908satok suggestedWords.setShouldBlockAutoCorrection(); 17892aa1dd45c44295e2f7e8ece1b520032d86b9f908satok } 17907e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(suggestedWords); 17917e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestedWords.size() > 0) { 17922aa1dd45c44295e2f7e8ece1b520032d86b9f908satok if (shouldBlockAutoCorrectionBySafetyNet) { 1793117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mWordComposer.setAutoCorrection(typedWord); 179482411d47ba7e8133ed2390c6920945e139a738cesatok } else if (suggestedWords.hasAutoCorrectionWord()) { 1795117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mWordComposer.setAutoCorrection(suggestedWords.getWord(1)); 1796923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1797117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mWordComposer.setAutoCorrection(typedWord); 1798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1799923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } else { 1800117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard // TODO: replace with mWordComposer.deleteAutoCorrection()? 1801117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard mWordComposer.setAutoCorrection(null); 1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1803913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 1804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1805923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1806f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard private void commitCurrentAutoCorrection(final int separatorCodePoint, 1807f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard final InputConnection ic) { 1808913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Complete any pending suggestions query first 1809d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka if (mHandler.hasPendingUpdateSuggestions()) { 1810d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka mHandler.cancelUpdateSuggestions(); 1811923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project updateSuggestions(); 1812923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1813117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); 1814117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard if (autoCorrection != null) { 1815117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard final String typedWord = mWordComposer.getTypedWord(); 181646798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard if (TextUtils.isEmpty(typedWord)) { 181746798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard throw new RuntimeException("We have an auto-correction but the typed word " 181846798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard + "is empty? Impossible! I must commit suicide."); 181946798d8f1f3d9012433d000790ba30ba910c0fa0Jean Chalard } 1820f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); 18214733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 18220fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard commitChosenWord(autoCorrection, WordComposer.COMMIT_TYPE_DECIDED_WORD); 1823f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard // Add the word to the user unigram dictionary if it's not a known word 1824117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard addToUserUnigramAndBigramDictionaries(autoCorrection, 1825f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard UserUnigramDictionary.FREQUENCY_FOR_TYPED); 1826f3ca6a59a7d6336fc318fe15467a1b447dc3ec4bJean Chalard if (!typedWord.equals(autoCorrection) && null != ic) { 18271c6cf26c3705e845418a29718c034598b52293ccJean Chalard // This will make the correction flash for a short while as a visual clue 18281c6cf26c3705e845418a29718c034598b52293ccJean Chalard // to the user that auto-correction happened. 18291c6cf26c3705e845418a29718c034598b52293ccJean Chalard InputConnectionCompatUtils.commitCorrection(ic, 18301c6cf26c3705e845418a29718c034598b52293ccJean Chalard mLastSelectionEnd - typedWord.length(), typedWord, autoCorrection); 18311c6cf26c3705e845418a29718c034598b52293ccJean Chalard } 1832923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1835c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka @Override 1836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void pickSuggestionManually(int index, CharSequence suggestion) { 1837604d80c67185954d4691ac775be59c499eee3b1csatok mComposingStateManager.onFinishComposingText(); 1838913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka SuggestedWords suggestions = mSuggestionsView.getSuggestions(); 183917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, 184017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard mSettingsValues.mWordSeparators); 18414f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett 18429351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 18439a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic != null) { 18449a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa ic.beginBatchEdit(); 18459a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 1846dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mApplicationSpecifiedCompletionOn 1847dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && mApplicationSpecifiedCompletions != null 18481b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka && index >= 0 && index < mApplicationSpecifiedCompletions.length) { 1849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 18509351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; 18519351550dc6af7859e5280e16144c9386a37b976dKen Wakasa ic.commitCompletion(completionInfo); 1852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1853913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (mSuggestionsView != null) { 1854913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsView.clear(); 1855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1856b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 18579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic != null) { 18589a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa ic.endBatchEdit(); 18599a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 1860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 1861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 18626a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 18636a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani // If this is a punctuation, apply it through the normal key press 186417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0)) 186517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) { 1866979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // Word separators are suggested before the user inputs something. 1867979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // So, LatinImeLogger logs "" as a user's input. 1868979f8690967ff5409fe18f5085858ccdb8e0ccf1satok LatinImeLogger.logOnManualSuggestion( 18697e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka "", suggestion.toString(), index, suggestions.mWords); 1870863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // Find out whether the previous character is a space. If it is, as a special case 1871120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // for punctuation entered through the suggestion strip, it should be swapped 1872120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // if it was a magic or a weak space. This is meant to help in case the user 1873863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // pressed space on purpose of displaying the suggestion strip punctuation. 187483ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa final int rawPrimaryCode = suggestion.charAt(0); 187583ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa // Maybe apply the "bidi mirrored" conversions for parentheses 18763708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 187749426a1ea941c0331a6e573e36cff3c3a8e8849cTadashi G. Takaoka final boolean isRtl = keyboard != null && keyboard.mIsRtlKeyboard; 187849426a1ea941c0331a6e573e36cff3c3a8e8849cTadashi G. Takaoka final int primaryCode = Key.getRtlParenthesisCode(rawPrimaryCode, isRtl); 187983ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa 1880120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard insertPunctuationFromSuggestionStrip(ic, primaryCode); 1881120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // TODO: the following endBatchEdit seems useless, check 18829a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic != null) { 18839a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa ic.endBatchEdit(); 18849a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 18856a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani return; 18866a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 18874733609947c0ec74e460bd714fffca0518ade93aJean Chalard mExpectingUpdateSelection = true; 18880fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard commitChosenWord(suggestion, WordComposer.COMMIT_TYPE_MANUAL_PICK); 18899468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani // Add the word to the auto dictionary if it's not a known word 18900c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani if (index == 0) { 1891f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard addToUserUnigramAndBigramDictionaries(suggestion, 1892f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard UserUnigramDictionary.FREQUENCY_FOR_PICKED); 1893979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } else { 1894bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok addToOnlyBigramDictionary(suggestion, 1); 18950c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani } 1896196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // TODO: the following is fishy, because it seems there may be cases where we are not 1897196d82cdd740580ed79d801483dbc282be85d076Jean Chalard // composing a word at all. Maybe throw an exception if !mWordComposer.isComposingWord() ? 18983651220327c051d8017045aa5e8919461507b3f8Jean Chalard LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), 18999318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa suggestion.toString(), index, suggestions.mWords); 1900923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // Follow it with a space 1901dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard if (mInputAttributes.mInsertSpaceOnPickSuggestionManually) { 19020730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard sendMagicSpace(); 1903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1904979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1905c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // We should show the "Touch again to save" hint if the user pressed the first entry 1906c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND either: 19077f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is no dictionary (we know that because we tried to load it => null != mSuggest 1908c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa // AND mSuggest.hasMainDictionary() is false) 19097f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // - There is a dictionary and the word is not in it 19107f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // Please note that if mSuggest is null, it means that everything is off: suggestion 19117f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // and correction, so we shouldn't try to show the hint 19127f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // We used to look at mCorrectionMode here, but showing the hint should have nothing 19137f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard // to do with the autocorrection setting. 1914bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null 1915bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If there is no dictionary the hint should be shown. 1916c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa && (!mSuggest.hasMainDictionary() 1917bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok // If "suggestion" is not in the dictionary, the hint should be shown. 1918bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok || !AutoCorrection.isValidWord( 1919bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok mSuggest.getUnigramDictionaries(), suggestion, true)); 1920b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 1921406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE, 1922406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard WordComposer.NOT_A_COORDINATE); 1923777118a40a363ccab69a00016d3156066513cb78Jean Chalard if (!showingAddToDictionaryHint) { 1924364da8c618303a7764595d2c15ee034a7671365dKen Wakasa // If we're not showing the "Touch again to save", then show corrections again. 1925979f8690967ff5409fe18f5085858ccdb8e0ccf1satok // In case the cursor position doesn't change, make sure we show the suggestions again. 192641ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard updateBigramPredictions(); 192741ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // Updating the predictions right away may be slow and feel unresponsive on slower 192841ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // terminals. On the other hand if we just postUpdateBigramPredictions() it will 192941ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard // take a noticeable delay to update them which may feel uneasy. 1930979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 1931b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani if (showingAddToDictionaryHint) { 193288562bec54658840dcce352127bdc15705c20a89Jean Chalard if (mIsUserDictionaryAvailable) { 1933644d33d60ea5a87501274488013d65f55238895eKen Wakasa mSuggestionsView.showAddToDictionaryHint( 1934644d33d60ea5a87501274488013d65f55238895eKen Wakasa suggestion, mSettingsValues.mHintToSaveText); 1935ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka } else { 1936ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 1937ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka } 193866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 19399a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa if (ic != null) { 19409a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa ic.endBatchEdit(); 19419a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa } 1942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1943a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 1944979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 19458558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa * Commits the chosen word to the text field and saves it for later retrieval. 1946979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 19470fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard private void commitChosenWord(final CharSequence bestWord, final int commitType) { 19489351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final KeyboardSwitcher switcher = mKeyboardSwitcher; 1949b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (!switcher.isKeyboardAvailable()) 19501679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka return; 19519351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 1952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic != null) { 19531fef530ec7626fa16777f52b48191e61db8f46d4satok mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); 19541531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard if (mSettingsValues.mEnableSuggestionSpanInsertion) { 19551531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); 19561531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( 19571531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard this, bestWord, suggestedWords), 1); 19581531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard } else { 19591531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard ic.commitText(bestWord, 1); 19601531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard } 1961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 19620fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // TODO: figure out here if this is an auto-correct or if the best word is actually 19630fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // what user typed. Note: currently this is done much later in 19640fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // WordComposer#didAutoCorrectToAnotherWord by string equality of the remembered 19650fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard // strings. 19660fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard mWordComposer.onCommitWord(commitType); 1967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 1968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 196989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard private static final WordComposer sEmptyWordComposer = new WordComposer(); 197041ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard public void updateBigramPredictions() { 197189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (mSuggest == null || !isSuggestionsRequested()) 197289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard return; 197389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 197417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (!mSettingsValues.mBigramPredictionEnabled) { 1975cb3320179d39a7983874697a0aa428b127675c9dJean Chalard setPunctuationSuggestions(); 1976cb3320179d39a7983874697a0aa428b127675c9dJean Chalard return; 1977cb3320179d39a7983874697a0aa428b127675c9dJean Chalard } 1978cb3320179d39a7983874697a0aa428b127675c9dJean Chalard 197989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(), 198017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard mSettingsValues.mWordSeparators); 1981904baab25a4c6ec5d9c4bf7e562154e3f544d296satok SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(sEmptyWordComposer, 19823708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka prevWord, mKeyboardSwitcher.getKeyboard().getProximityInfo(), mCorrectionMode); 198389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 198489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (builder.size() > 0) { 198589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // Explicitly supply an empty typed word (the no-second-arg version of 198689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard // showSuggestions will retrieve the word near the cursor, we don't want that here) 198789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard showSuggestions(builder.build(), ""); 198889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } else { 198989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard if (!isShowingPunctuationList()) setPunctuationSuggestions(); 199089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 199189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard } 199289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard 19937a8dac55278cedd838be325f56b4c52d973c61f5satok public void setPunctuationSuggestions() { 199417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard setSuggestions(mSettingsValues.mSuggestPuncList); 1995913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setSuggestionStripShown(isSuggestionsStripVisible()); 19966a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani } 19976a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1998f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard private void addToUserUnigramAndBigramDictionaries(CharSequence suggestion, 1999f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard int frequencyDelta) { 2000979f8690967ff5409fe18f5085858ccdb8e0ccf1satok checkAddToDictionary(suggestion, frequencyDelta, false); 2001979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 2002979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2003bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) { 2004979f8690967ff5409fe18f5085858ccdb8e0ccf1satok checkAddToDictionary(suggestion, frequencyDelta, true); 2005979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 2006979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2007979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 2008f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard * Adds to the UserBigramDictionary and/or UserUnigramDictionary 2009bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible 2010979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 2011979f8690967ff5409fe18f5085858ccdb8e0ccf1satok private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta, 2012bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok boolean selectedANotTypedWord) { 2013979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (suggestion == null || suggestion.length() < 1) return; 2014bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 20150c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be 20160c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // adding words in situations where the user or application really didn't 20170c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani // want corrections enabled or learned. 2018979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (!(mCorrectionMode == Suggest.CORRECTION_FULL 2019979f8690967ff5409fe18f5085858ccdb8e0ccf1satok || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) { 2020979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return; 2021979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 2022bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok 20235955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard if (null != mSuggest && null != mUserUnigramDictionary) { 20245955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard final boolean selectedATypedWordAndItsInUserUnigramDic = 20255955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard !selectedANotTypedWord && mUserUnigramDictionary.isValidWord(suggestion); 20265955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard final boolean isValidWord = AutoCorrection.isValidWord( 20275955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard mSuggest.getUnigramDictionaries(), suggestion, true); 20285955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard final boolean needsToAddToUserUnigramDictionary = 20295955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard selectedATypedWordAndItsInUserUnigramDic || !isValidWord; 20305955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard if (needsToAddToUserUnigramDictionary) { 20315955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard mUserUnigramDictionary.addWord(suggestion.toString(), frequencyDelta); 20325955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard } 2033e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 2034979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2035e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka if (mUserBigramDictionary != null) { 2036863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // We don't want to register as bigrams words separated by a separator. 2037863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // For example "I will, and you too" : we don't want the pair ("will" "and") to be 2038863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard // a bigram. 203940f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final InputConnection ic = getCurrentInputConnection(); 204040f7efc172928bdd6048e91421a766abe5b22996Jean Chalard if (null != ic) { 204140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard final CharSequence prevWord = 204240f7efc172928bdd6048e91421a766abe5b22996Jean Chalard EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators); 204340f7efc172928bdd6048e91421a766abe5b22996Jean Chalard if (!TextUtils.isEmpty(prevWord)) { 204440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString()); 204540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard } 2046979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 204732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 204832e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani } 204932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani 20507a8dac55278cedd838be325f56b4c52d973c61f5satok public boolean isCursorTouchingWord() { 20519351550dc6af7859e5280e16144c9386a37b976dKen Wakasa final InputConnection ic = getCurrentInputConnection(); 2052923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (ic == null) return false; 2053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project CharSequence toLeft = ic.getTextBeforeCursor(1, 0); 2054923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project CharSequence toRight = ic.getTextAfterCursor(1, 0); 2055923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (!TextUtils.isEmpty(toLeft) 205617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard && !mSettingsValues.isWordSeparator(toLeft.charAt(0)) 205717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) { 2058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 2059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2060a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker if (!TextUtils.isEmpty(toRight) 206117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard && !mSettingsValues.isWordSeparator(toRight.charAt(0)) 206217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) { 2063923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return true; 2064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return false; 2066923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2067a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2068120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // "ic" must not be null 20698fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { 2070dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); 2071dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani return TextUtils.equals(text, beforeText); 2072dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani } 2073dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani 2074120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // "ic" must not be null 20756b1f500da451de56932a8b2a99c63857994ece85Jean Chalard /** 20766b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * Check if the cursor is actually at the end of a word. If so, restart suggestions on this 20776b1f500da451de56932a8b2a99c63857994ece85Jean Chalard * word, else do nothing. 20786b1f500da451de56932a8b2a99c63857994ece85Jean Chalard */ 20796b1f500da451de56932a8b2a99c63857994ece85Jean Chalard private void restartSuggestionsOnWordBeforeCursorIfAtEndOfWord( 20806b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final InputConnection ic) { 20816b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Bail out if the cursor is not at the end of a word (cursor must be preceded by 20826b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // non-whitespace, non-separator, non-start-of-text) 20836b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Example ("|" is the cursor here) : <SOL>"|a" " |a" " | " all get rejected here. 20846b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence textBeforeCursor = ic.getTextBeforeCursor(1, 0); 20856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (TextUtils.isEmpty(textBeforeCursor) 20866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard || mSettingsValues.isWordSeparator(textBeforeCursor.charAt(0))) return; 20876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20886b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Bail out if the cursor is in the middle of a word (cursor must be followed by whitespace, 20896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // separator or end of line/text) 20906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Example: "test|"<EOL> "te|st" get rejected here 20916b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence textAfterCursor = ic.getTextAfterCursor(1, 0); 20926b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (!TextUtils.isEmpty(textAfterCursor) 20936b1f500da451de56932a8b2a99c63857994ece85Jean Chalard && !mSettingsValues.isWordSeparator(textAfterCursor.charAt(0))) return; 20946b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 20956b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Bail out if word before cursor is 0-length or a single non letter (like an apostrophe) 20966b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Example: " '|" gets rejected here but "I'|" and "I|" are okay 20976b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence word = EditingUtils.getWordAtCursor(ic, mSettingsValues.mWordSeparators); 20986b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (TextUtils.isEmpty(word)) return; 20996b1f500da451de56932a8b2a99c63857994ece85Jean Chalard if (word.length() == 1 && !Character.isLetter(word.charAt(0))) return; 21006b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 21016b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // Okay, we are at the end of a word. Restart suggestions. 21026b1f500da451de56932a8b2a99c63857994ece85Jean Chalard restartSuggestionsOnWordBeforeCursor(ic, word); 21036b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 21046b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 21056b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // "ic" must not be null 21066b1f500da451de56932a8b2a99c63857994ece85Jean Chalard private void restartSuggestionsOnWordBeforeCursor(final InputConnection ic, 21076b1f500da451de56932a8b2a99c63857994ece85Jean Chalard final CharSequence word) { 21083708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka mWordComposer.setComposingWord(word, mKeyboardSwitcher.getKeyboard()); 21096b1f500da451de56932a8b2a99c63857994ece85Jean Chalard mComposingStateManager.onStartComposingText(); 21106b1f500da451de56932a8b2a99c63857994ece85Jean Chalard ic.deleteSurroundingText(word.length(), 0); 21116b1f500da451de56932a8b2a99c63857994ece85Jean Chalard ic.setComposingText(word, 1); 21126b1f500da451de56932a8b2a99c63857994ece85Jean Chalard mHandler.postUpdateSuggestions(); 21136b1f500da451de56932a8b2a99c63857994ece85Jean Chalard } 21146b1f500da451de56932a8b2a99c63857994ece85Jean Chalard 21156b1f500da451de56932a8b2a99c63857994ece85Jean Chalard // "ic" must not be null 2116890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard private void cancelAutoCorrect(final InputConnection ic) { 21179e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard mWordComposer.resumeSuggestionOnKeptWord(); 21189e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard final String originallyTypedWord = mWordComposer.getTypedWord(); 21199e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard final CharSequence autoCorrectedTo = mWordComposer.getAutoCorrectionOrNull(); 21209e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard final int cancelLength = autoCorrectedTo.length(); 2121890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard final CharSequence separator = ic.getTextBeforeCursor(1, 0); 2122890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2123890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard final String wordBeforeCursor = 2124890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) 2125890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard .toString(); 21269e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard if (!autoCorrectedTo.equals(wordBeforeCursor)) { 2127890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard throw new RuntimeException("cancelAutoCorrect check failed: we thought we were " 21289e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard + "reverting \"" + autoCorrectedTo 2129890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" + wordBeforeCursor + "\""); 2130890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 21319e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard if (originallyTypedWord.equals(wordBeforeCursor)) { 2132890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard throw new RuntimeException("cancelAutoCorrect check failed: we wanted to cancel " 21339e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard + "auto correction and revert to \"" + originallyTypedWord 2134890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\" but we found this very string before the cursor"); 2135890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 21368558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa } 2137890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard ic.deleteSurroundingText(cancelLength + 1, 0); 21389e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard ic.commitText(originallyTypedWord, 1); 2139c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard // Re-insert the separator 2140890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard ic.commitText(separator, 1); 21419e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard mWordComposer.deleteAutoCorrection(); 21420fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_CANCEL_AUTO_CORRECT); 2143406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, 2144406d192a9e8f07ed6c6a408650feb0a757ca388eJean Chalard WordComposer.NOT_A_COORDINATE); 2145890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard mHandler.cancelUpdateBigramPredictions(); 2146890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard mHandler.postUpdateSuggestions(); 2147890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2148890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 2149890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard // "ic" must not be null 2150890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard private void restartSuggestionsOnManuallyPickedTypedWord(final InputConnection ic) { 2151c2a76a1529870b59bba133a7d76a800cbd20ecfaJean Chalard final int restartLength = mWordComposer.size(); 2152890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (DEBUG) { 2153890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard final String wordBeforeCursor = 2154890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard ic.getTextBeforeCursor(restartLength + 1, 0).subSequence(0, restartLength) 2155890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard .toString(); 2156890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard if (!mWordComposer.getTypedWord().equals(wordBeforeCursor)) { 2157890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard throw new RuntimeException("restartSuggestionsOnManuallyPickedTypedWord " 2158890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "check failed: we thought we were reverting \"" 2159890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + mWordComposer.getTypedWord() 2160890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + "\", but before the cursor we found \"" 2161890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard + wordBeforeCursor + "\""); 2162890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard } 2163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2164890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard ic.deleteSurroundingText(restartLength + 1, 0); 2165890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard 2166890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard // Note: this relies on the last word still being held in the WordComposer 2167890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard // Note: in the interest of code simplicity, we may want to just call 2168890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving 2169890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard // the old WordComposer allows to reuse the actual typed coordinates. 2170c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard mWordComposer.resumeSuggestionOnKeptWord(); 2171890d13189d8dd305681bcb00d09f34d3ae68c648Jean Chalard ic.setComposingText(mWordComposer.getTypedWord(), 1); 21728558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa mHandler.cancelUpdateBigramPredictions(); 21738558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa mHandler.postUpdateSuggestions(); 2174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2176120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // "ic" must not be null 21779351550dc6af7859e5280e16144c9386a37b976dKen Wakasa private boolean revertDoubleSpace(final InputConnection ic) { 21784733609947c0ec74e460bd714fffca0518ade93aJean Chalard mHandler.cancelDoubleSpacesTimer(); 21794733609947c0ec74e460bd714fffca0518ade93aJean Chalard // Here we test whether we indeed have a period and a space before us. This should not 21804733609947c0ec74e460bd714fffca0518ade93aJean Chalard // be needed, but it's there just in case something went wrong. 21814733609947c0ec74e460bd714fffca0518ade93aJean Chalard final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); 21828ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard if (!". ".equals(textBeforeCursor)) { 21838ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard // We should not have come here if we aren't just after a ". ". 21848ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard throw new RuntimeException("Tried to revert double-space combo but we didn't find " 21858ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard + "\". \" just before the cursor."); 21868ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard } 21874733609947c0ec74e460bd714fffca0518ade93aJean Chalard ic.beginBatchEdit(); 21884733609947c0ec74e460bd714fffca0518ade93aJean Chalard ic.deleteSurroundingText(2, 0); 21894733609947c0ec74e460bd714fffca0518ade93aJean Chalard ic.commitText(" ", 1); 21904733609947c0ec74e460bd714fffca0518ade93aJean Chalard ic.endBatchEdit(); 21914733609947c0ec74e460bd714fffca0518ade93aJean Chalard return true; 21924733609947c0ec74e460bd714fffca0518ade93aJean Chalard } 21934733609947c0ec74e460bd714fffca0518ade93aJean Chalard 21948fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka private static boolean revertSwapPunctuation(final InputConnection ic) { 2195120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // Here we test whether we indeed have a space and something else before us. This should not 2196120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // be needed, but it's there just in case something went wrong. 2197120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); 2198120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to 2199120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard // enter surrogate pairs this code will have been removed. 22008ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard if (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1)) { 22018ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard // We should not have come here if the text before the cursor is not a space. 22029de5cfc67a4e349c547e40678add27cdd6ca8490Jean Chalard throw new RuntimeException("Tried to revert a swap of punctuation but we didn't " 22038ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard + "find a space just before the cursor."); 22048ad4013406e5e94967bb74baae3b068187f62e4bJean Chalard } 2205120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.beginBatchEdit(); 2206120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.deleteSurroundingText(2, 0); 2207120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1); 2208120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard ic.endBatchEdit(); 2209120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard return true; 2210120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard } 2211120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard 2212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean isWordSeparator(int code) { 221317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard return mSettingsValues.isWordSeparator(code); 2214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22160730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard private void sendMagicSpace() { 2217571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka sendKeyChar((char)Keyboard.CODE_SPACE); 2218120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard mSpaceState = SPACE_STATE_MAGIC; 2219b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mKeyboardSwitcher.updateShiftState(); 2220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean preferCapitalization() { 22239318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa return mWordComposer.isFirstCharCapitalized(); 2224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 222688fc9d44186120f9edc5cf7ec0e2af85260fed04satok // Notify that language or mode have been changed and toggleLanguage will update KeyboardID 2227c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka // according to new language or mode. 2228c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka public void onRefreshKeyboard() { 222955303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { 223055303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka // Before Honeycomb, Voice IME is in LatinIME and it changes the current input view, 223155303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka // so that we need to re-create the keyboard input view here. 223255303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka setInputView(mKeyboardSwitcher.onCreateInputView()); 223355303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka } 22341e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // When the device locale is changed in SetupWizard etc., this method may get called via 22351e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // onConfigurationChanged before SoftInputWindow is shown. 22361e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka if (mKeyboardSwitcher.getKeyboardView() != null) { 22371e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka // Reload keyboard because the current language has been changed. 22381e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettingsValues); 22391e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka } 22400ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok initSuggest(); 224117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard loadSettings(); 224236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani } 224336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani 2244d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka private void hapticAndAudioFeedback(int primaryCode) { 2245d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka vibrate(); 2246d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka playKeyClick(primaryCode); 2247d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka } 2248d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka 22495a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 2250e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onPress(int primaryCode, boolean withSliding) { 2251055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final KeyboardSwitcher switcher = mKeyboardSwitcher; 2252055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (switcher.isVibrateAndSoundFeedbackRequired()) { 2253d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka hapticAndAudioFeedback(primaryCode); 2254cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 22551679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); 2256571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) { 2257e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka switcher.onPressShift(withSliding); 2258e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { 22596c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka switcher.onPressSymbol(); 226040a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka } else { 22616c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka switcher.onOtherKeyPressed(); 2262681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka } 2263923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22655a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 2266e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onRelease(int primaryCode, boolean withSliding) { 22671679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka KeyboardSwitcher switcher = mKeyboardSwitcher; 22683f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani // Reset any drag flags in the keyboard 22691679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka final boolean distinctMultiTouch = switcher.hasDistinctMultitouch(); 2270571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) { 2271e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka switcher.onReleaseShift(withSliding); 2272e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { 22736c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka switcher.onReleaseSymbol(); 227440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka } 2275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2276a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2277a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2278123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka // receive ringer mode change and network state change. 2279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private BroadcastReceiver mReceiver = new BroadcastReceiver() { 2280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 2281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onReceive(Context context, Intent intent) { 2282123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka final String action = intent.getAction(); 2283123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) { 2284123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka updateRingerMode(); 2285123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 2286123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka mSubtypeSwitcher.onNetworkStateChanged(intent); 2287123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka } 2288923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project }; 2290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // update flags for silent mode 2292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void updateRingerMode() { 2293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mAudioManager == null) { 2294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 2295bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa if (mAudioManager == null) return; 2296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2297bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL); 2298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private void playKeyClick(int primaryCode) { 2301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // if mAudioManager is null, we don't have the ringer state yet 2302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project // mAudioManager will be set by updateRingerMode 2303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mAudioManager == null) { 2304c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka if (mKeyboardSwitcher.getKeyboardView() != null) { 2305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project updateRingerMode(); 2306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 230817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (isSoundOn()) { 2309f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa final int sound; 2310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (primaryCode) { 2311f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa case Keyboard.CODE_DELETE: 2312f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa sound = AudioManager.FX_KEYPRESS_DELETE; 2313f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa break; 2314f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa case Keyboard.CODE_ENTER: 2315f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa sound = AudioManager.FX_KEYPRESS_RETURN; 2316f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa break; 2317f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa case Keyboard.CODE_SPACE: 2318f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa sound = AudioManager.FX_KEYPRESS_SPACEBAR; 2319f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa break; 2320f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa default: 2321f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa sound = AudioManager.FX_KEYPRESS_STANDARD; 2322f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa break; 2323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2324c207e0a7dad0bdae054be47cafe878698f9401fcJean Chalard mAudioManager.playSoundEffect(sound, mSettingsValues.mFxVolume); 2325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2328409220583333bdf06290dd9fd42f91b5c0d1b11asatok public void vibrate() { 232917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard if (!mSettingsValues.mVibrateOn) { 2330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project return; 2331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2332c207e0a7dad0bdae054be47cafe878698f9401fcJean Chalard if (mSettingsValues.mKeypressVibrationDuration < 0) { 233328f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa // Go ahead with the system default 233428f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); 233528f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa if (inputView != null) { 233628f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa inputView.performHapticFeedback( 233728f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa HapticFeedbackConstants.KEYBOARD_TAP, 233828f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 233928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa } 234028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa } else if (mVibrator != null) { 2341c207e0a7dad0bdae054be47cafe878698f9401fcJean Chalard mVibrator.vibrate(mSettingsValues.mKeypressVibrationDuration); 2342923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2344923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2345f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard public boolean isAutoCapitalized() { 2346f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard return mWordComposer.isAutoCapitalized(); 23476516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani } 23486516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani 234917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard boolean isSoundOn() { 235017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard return mSettingsValues.mSoundOn && !mSilentModeOn; 2351979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 2352979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2353e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani private void updateCorrectionMode() { 23549f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok // TODO: cleanup messy flags 2355f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled 2356dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard && !mInputAttributes.mInputTypeNoAutoCorrect; 2357283b0c2b642030539ba3e41f3f54b6aed6bb9e2dJean Chalard mCorrectionMode = shouldAutoCorrect ? Suggest.CORRECTION_FULL : Suggest.CORRECTION_NONE; 2358283b0c2b642030539ba3e41f3f54b6aed6bb9e2dJean Chalard mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect) 2359979f8690967ff5409fe18f5085858ccdb8e0ccf1satok ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode; 2360e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani } 2361e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani 23622ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka private void updateSuggestionVisibility(final Resources res) { 23630fe3611bee5095e7bd0fff2d0fdf8d5a13379132Jean Chalard final String suggestionVisiblityStr = mSettingsValues.mShowSuggestionsSetting; 23647599cfea4a2d56f4779452ec8e8742f7b9629cc0satok for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) { 2365458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa if (suggestionVisiblityStr.equals(res.getString(visibility))) { 23667599cfea4a2d56f4779452ec8e8742f7b9629cc0satok mSuggestionVisibility = visibility; 23677599cfea4a2d56f4779452ec8e8742f7b9629cc0satok break; 23687599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 23697599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 23707599cfea4a2d56f4779452ec8e8742f7b9629cc0satok } 23717599cfea4a2d56f4779452ec8e8742f7b9629cc0satok 2372466741d8a78965b8509bf527344f289e50873092Mike LeBeau protected void launchSettings() { 2373cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa launchSettingsClass(Settings.class); 2374466741d8a78965b8509bf527344f289e50873092Mike LeBeau } 2375466741d8a78965b8509bf527344f289e50873092Mike LeBeau 2376bf96661d33d0126adb60a48880ceba1ff055d4a4satok public void launchDebugSettings() { 2377cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa launchSettingsClass(DebugSettings.class); 2378bf96661d33d0126adb60a48880ceba1ff055d4a4satok } 2379bf96661d33d0126adb60a48880ceba1ff055d4a4satok 2380cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa protected void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) { 2381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project handleClose(); 2382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project Intent intent = new Intent(); 2383466741d8a78965b8509bf527344f289e50873092Mike LeBeau intent.setClass(LatinIME.this, settingsClass); 2384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project startActivity(intent); 2386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 23882fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showSubtypeSelectorAndSettings() { 238985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 239085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 239185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka // TODO: Should use new string "Select active input modes". 239285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.language_selection_title), 239385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.english_ime_settings), 239485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 239585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 23962fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka @Override 23972fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka public void onClick(DialogInterface di, int position) { 23982fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka di.dismiss(); 23992fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka switch (position) { 240085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 24012cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok Intent intent = CompatUtils.getInputLanguageSelectionIntent( 24022a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Utils.getInputMethodId(mImm, getPackageName()), 24032a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard Intent.FLAG_ACTIVITY_NEW_TASK 24042fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 24052fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka | Intent.FLAG_ACTIVITY_CLEAR_TOP); 24062fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka startActivity(intent); 24072fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2408aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa case 1: 2409aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa launchSettings(); 2410aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa break; 24112fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 24122fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 241385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2414bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2415bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2416bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2417bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka showOptionDialogInternal(builder.create()); 24182fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka } 2419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 24202fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka private void showOptionsMenu() { 242185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence title = getString(R.string.english_ime_input_options); 242285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final CharSequence[] items = new CharSequence[] { 242385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.selectInputMethod), 242485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka getString(R.string.english_ime_settings), 242585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 242685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { 24275a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka @Override 2428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void onClick(DialogInterface di, int position) { 2429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project di.dismiss(); 2430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project switch (position) { 243185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 0: 2432ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka mImm.showInputMethodPicker(); 24332fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 243485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka case 1: 2435ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka launchSettings(); 24362fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka break; 2437923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2438923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 243985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka }; 2440bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka final AlertDialog.Builder builder = new AlertDialog.Builder(this) 2441bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setItems(items, listener) 2442bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka .setTitle(title); 2443bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka showOptionDialogInternal(builder.create()); 2444923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2445923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 24467e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka @Override 24477e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 2448923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super.dump(fd, fout, args); 2449a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker 2450923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project final Printer p = new PrintWriterPrinter(fout); 2451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println("LatinIME state :"); 24523708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); 2453df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1; 2454df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka p.println(" Keyboard mode = " + keyboardMode); 2455dc9d0fcc11f0886296c6eb325fe4f71beb87ff4cJean Chalard p.println(" mIsSuggestionsRequested=" + mInputAttributes.mIsSettingsSuggestionStripOn); 2456923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project p.println(" mCorrectionMode=" + mCorrectionMode); 24574d0f03bd66742ee292da81a3e025e119f28b6940Jean Chalard p.println(" isComposingWord=" + mWordComposer.isComposingWord()); 245817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard p.println(" mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled); 245917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard p.println(" mSoundOn=" + mSettingsValues.mSoundOn); 246017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard p.println(" mVibrateOn=" + mSettingsValues.mVibrateOn); 2461240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard p.println(" mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn); 24626fa003ee234c6e2ca6cd9ec555221ac5c71a5405Jean Chalard p.println(" mInputAttributes=" + mInputAttributes.toString()); 2463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 2464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 2465