LatinIME.java revision f733074aaecdfd6e89cfee2daff8a9c1233b60f1
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
192cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatokimport com.android.inputmethod.compat.CompatUtils;
20b2707856aba4fc9b063f26305f1fb603b19c1701satokimport com.android.inputmethod.compat.EditorInfoCompatUtils;
21b2707856aba4fc9b063f26305f1fb603b19c1701satokimport com.android.inputmethod.compat.InputConnectionCompatUtils;
22610f1dc8553cf2ed97e763a06a19380c4a6cd636satokimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
2310dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatokimport com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
24e9957752bcaad048746c7a57bbd2c0a59e1918a0satokimport com.android.inputmethod.compat.InputTypeCompatUtils;
25699e429f1913197650cc2fc2d8cb6e506be66842satokimport com.android.inputmethod.compat.VibratorCompatWrapper;
2688fc9d44186120f9edc5cf7ec0e2af85260fed04satokimport com.android.inputmethod.deprecated.LanguageSwitcherProxy;
27e9957752bcaad048746c7a57bbd2c0a59e1918a0satokimport com.android.inputmethod.deprecated.VoiceProxy;
28f733074aaecdfd6e89cfee2daff8a9c1233b60f1satokimport com.android.inputmethod.deprecated.recorrection.Recorrection;
295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
305a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
31571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
325a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
33de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
35388ce92ab8a635c5ad44620dad59baf05dfea510Amith Yamasani
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
4436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
47123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
5018e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasaimport android.os.IBinder;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
53bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
55e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
57979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
59923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
6166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
63e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.LayoutInflater;
64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
658e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
668e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
70923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
71466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
7340ac45ebdcd71940394dda00371d4847f7db0f26Ken Wakasaimport android.widget.LinearLayout;
74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
75466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
76466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
77b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimodaimport java.util.Arrays;
78466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
79466741d8a78965b8509bf527344f289e50873092Mike LeBeau
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
8310dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatokpublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener {
848efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    private static final String TAG = LatinIME.class.getSimpleName();
85979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
86409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
87910b73127fa207dd26ec8124000262523b0aac0csatok    private static boolean DEBUG = LatinImeLogger.sDBG;
88a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     *
948efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
9610dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok    @SuppressWarnings("dep-ann")
978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
1008efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
1018efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
1028efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
1038efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1074199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1084199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1094199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1104199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1118efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
1129e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
113fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
117d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
118a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
119cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
120cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
121cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
122cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
123cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
124cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1257599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1287599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1377599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1387599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
139e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
1407a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka    private int mCandidateStripHeight;
141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
144a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
146a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
147610f1dc8553cf2ed97e763a06a19380c4a6cd636satok    private InputMethodManagerCompatWrapper mImm;
1482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
15171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1520ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
153b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    private VoiceProxy mVoiceProxy;
1547a8dac55278cedd838be325f56b4c52d973c61f5satok    private Recorrection mRecorrection;
155a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
157979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1582bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1594ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
16036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1610730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // TODO: Create an inner class to group options and pseudo-options to improve readability.
162c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
1630730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mShouldInsertMagicSpace;
164c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
165c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
166c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
167c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
168dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette    private AccessibilityUtils mAccessibilityUtils;
169dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette
17071c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
173f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard    private boolean mHasUncommittedTypedChars;
174e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1750730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // Magic space: a space that should disappear on space/apostrophe insertion, move after the
1760730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // punctuation on punctuation insertion, and become a real space on alpha char insertion.
1770730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mJustAddedMagicSpace; // This indicates whether the last char is a magic space.
178e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
179b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
180979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mBigramSuggestionEnabled;
181b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    // Prediction: use bigrams to predict the next word when there is no input for it yet
182b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    private boolean mBigramPredictionEnabled;
183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
186979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mPopupOn;
187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
1886e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
1892fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private boolean mConfigEnableShowSubtypeSettings;
190363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka    private boolean mConfigSwipeDownDismissKeyboardEnabled;
191de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
1929b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa    private int mConfigDelayUpdateSuggestions;
1939b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa    private int mConfigDelayUpdateOldSuggestions;
1949b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa    private int mConfigDelayUpdateShiftState;
195de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDurationOfFadeoutLanguageOnSpacebar;
196d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka    private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
197fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka    private long mConfigDoubleSpacesTurnIntoPeriodTimeout;
198409220583333bdf06290dd9fd42f91b5c0d1b11asatok
19979efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
20079efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
20179efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
202979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
20379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
20479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
2057e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestPuncList;
206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
211a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
2132296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
21471c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
217979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /* package */ String mWordSeparators;
218863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private String mMagicSpaceStrippers;
219863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private String mMagicSpaceSwappers;
220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private String mSuggestPuncs;
221b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    // TODO: Move this flag to VoiceProxy
22281c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
223466741d8a78965b8509bf527344f289e50873092Mike LeBeau
224cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
225cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private BroadcastReceiver mDictionaryPackInstallReceiver =
226cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard            new DictionaryPackInstallBroadcastReceiver(this);
227cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
228dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
229dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
230dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
23136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
232571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
233d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
234409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
235d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
236d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
237d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
238d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
239de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
240de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
241fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        private static final int MSG_SPACE_TYPED = 6;
242cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
243d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
246de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
247de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
249d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
250d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
251d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
252d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
2539fbfd5877305ed19a20663630b498b6b3fdae942satok                mRecorrection.setRecorrectionSuggestions(mVoiceProxy, mCandidateView, mSuggest,
2549fbfd5877305ed19a20663630b498b6b3fdae942satok                        mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, mLastSelectionStart,
2559fbfd5877305ed19a20663630b498b6b3fdae942satok                        mLastSelectionEnd, mWordSeparators);
256d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
257d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
258de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
259d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
260cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            case MSG_SET_BIGRAM_PREDICTIONS:
261cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                updateBigramPredictions();
26289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                break;
263d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
264b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.handleVoiceResults(preferCapitalization()
265de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
266de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
267de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
268de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
26966432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
270d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
27166432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
272de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
273de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        mConfigDurationOfFadeoutLanguageOnSpacebar);
274de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
275de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
27766432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
278d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
279d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
283d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
2859b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS),
2869b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa                    mConfigDelayUpdateSuggestions);
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
294d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
295d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
296d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
297d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
298d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
299d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
3009b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa                    mConfigDelayUpdateOldSuggestions);
301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
302d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
304d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
306d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
3099b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mConfigDelayUpdateShiftState);
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
316cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void postUpdateBigramPredictions() {
317cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
3189b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS),
3199b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa                    mConfigDelayUpdateSuggestions);
32089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
32189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
322cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void cancelUpdateBigramPredictions() {
323cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
32489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
32589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
326d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
327d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
328d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
329de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
330d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
331de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
332de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
333de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
334de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
335050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
336c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The language is always displayed when the delay is negative.
337c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                final boolean needsToDisplayLanguage = localeChanged
338c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                        || mConfigDelayBeforeFadeoutLanguageOnSpacebar < 0;
339de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
340de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
341c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
342d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
343c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The fadeout animation will start when the delay is positive.
344d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
345de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
346de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                            mConfigDelayBeforeFadeoutLanguageOnSpacebar);
347de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
348de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
349de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
350fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
351fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void startDoubleSpacesTimer() {
352fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
353fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
354fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                    mConfigDoubleSpacesTurnIntoPeriodTimeout);
355fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
356fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
357fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void cancelDoubleSpacesTimer() {
358fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
359fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
360fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
361fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public boolean isAcceptingDoubleSpaces() {
362fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            return hasMessages(MSG_SPACE_TYPED);
363fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
364d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3667e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3677e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
36827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
36927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
37027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
3716d9021527a38ba1e94225020389621a0d7227aa1satok        LanguageSwitcherProxy.init(this, prefs);
37227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
37327d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
374dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        AccessibilityUtils.init(this, prefs);
3757a8dac55278cedd838be325f56b4c52d973c61f5satok        Recorrection.init(this, prefs);
376363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
377923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
378363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
379610f1dc8553cf2ed97e763a06a19380c4a6cd636satok        mImm = InputMethodManagerCompatWrapper.getInstance(this);
3808efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
3810ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3820ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
383dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils = AccessibilityUtils.getInstance();
3847a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection = Recorrection.getInstance();
385363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
386363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
387363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
388fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
3892fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mConfigEnableShowSubtypeSettings = res.getBoolean(
3902fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                R.bool.config_enable_show_subtype_settings);
391363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
392363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                R.bool.config_swipe_down_dismiss_keyboard_enabled);
393de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
394de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_delay_before_fadeout_language_on_spacebar);
3959b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa        mConfigDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions);
3969b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa        mConfigDelayUpdateOldSuggestions = res.getInteger(
3979b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa                R.integer.config_delay_update_old_suggestions);
3989b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa        mConfigDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state);
399de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
400de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_duration_of_fadeout_language_on_spacebar);
401d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
40266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
403fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        mConfigDoubleSpacesTurnIntoPeriodTimeout = res.getInteger(
404fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                R.integer.config_double_spaces_turn_into_period_timeout);
405979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4069502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
407979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
4089502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
409979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
4100ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
411979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
412979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
4139502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
414979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
415979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
416979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
417363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
4186a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
419b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
420cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Register to receive ringer mode change and network state change.
421cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Also receive installation and removal of a dictionary pack.
422123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
423123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
424123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
426b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
427cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
428cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final IntentFilter packageFilter = new IntentFilter();
429cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
430cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
431cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addDataScheme(SCHEME_PACKAGE);
432cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
433646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard
434646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        final IntentFilter newDictFilter = new IntentFilter();
435646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        newDictFilter.addAction(
436646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard                DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
437646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
438923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
43936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4400ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
441cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
442cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final Locale keyboardLocale = new Locale(localeStr);
44336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
444309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Resources res = mResources;
445309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
44636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
44736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
44836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
44927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
45089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
451979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4528efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
453cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
4541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
45527023341658b4cf5430d18ddb94fd9502ecfe3cbTadashi G. Takaoka        updateAutoTextEnabled();
456e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
457cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserDictionary = new UserDictionary(this, localeStr);
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
459e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
460e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4612bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
462e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
463cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO);
46434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
465e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
466cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER);
467e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
468e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
469e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
470863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        mMagicSpaceStrippers = res.getString(R.string.magic_space_stripping_symbols);
471863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        mMagicSpaceSwappers = res.getString(R.string.magic_space_swapping_symbols);
472863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        String wordSeparators = mMagicSpaceStrippers + mMagicSpaceSwappers
473863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                + res.getString(R.string.magic_space_promoting_symbols);
474863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        final String notWordSeparators = res.getString(R.string.non_word_separator_symbols);
475863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        for (int i = notWordSeparators.length() - 1; i >= 0; --i)
476863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            wordSeparators = wordSeparators.replace(notWordSeparators.substring(i, i + 1), "");
477863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        mWordSeparators = wordSeparators;
47836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
479309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        Utils.setSystemLocale(res, savedLocale);
480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
48136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
482cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /* package private */ void resetSuggestMainDict() {
483cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
484cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final Locale keyboardLocale = new Locale(localeStr);
485cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
486cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
487cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
488cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
489466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
490466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
491e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
492e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
493e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
494979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
496cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
497b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.destroy();
498979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
499979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
502923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
505dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
506b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
507b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
508466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
509466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
510466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
511b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
5122fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
5132fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
514b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
5158b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
51681c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
518b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.onConfigurationChanged(conf);
51981c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
52088fc9d44186120f9edc5cf7ec0e2af85260fed04satok
52188fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
52288fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.onConfigurationChanged(conf);
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
524b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
525923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
5278d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
529923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
532e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
533e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
534e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
5357a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height);
536e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
537923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
539e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
542a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
54445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
54545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5468e09172df1bb176cc899940862c56bed9b9aec4esatok
54789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (DEBUG) {
548910b73127fa207dd26ec8124000262523b0aac0csatok            Log.d(TAG, "onStartInputView: " + inputView);
549910b73127fa207dd26ec8124000262523b0aac0csatok        }
550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
551979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5558d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5564ab730dbd34fad323063f2ffd31ce33de746668dsatok
557662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        TextEntryState.reset();
5586c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
559c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
560c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
561c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
562b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        final VoiceProxy voiceIme = mVoiceProxy;
563e9957752bcaad048746c7a57bbd2c0a59e1918a0satok        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(attribute.inputType)
564e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                || InputTypeCompatUtils.isVisiblePasswordInputType(attribute.inputType));
565c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
566cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
567c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
568c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
569c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
570c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
571f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
572c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
5730730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
574c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
575c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        loadSettings(attribute);
576c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
577cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            switcher.loadKeyboard(attribute,
5784503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    mSubtypeSwitcher.isShortcutImeEnabled() && voiceIme.isVoiceButtonEnabled(),
5794503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    voiceIme.isVoiceButtonOnPrimary());
580c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
581c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
582c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
5837a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(), false /* needsInputViewShown */ );
584c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
585c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
586c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
587c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
588c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
589dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        final boolean accessibilityEnabled = mAccessibilityUtils.isAccessibilityEnabled();
590dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette
591d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka        inputView.setKeyPreviewEnabled(mPopupOn);
592c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
593dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        inputView.setAccessibilityEnabled(accessibilityEnabled);
594c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
5957a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.checkRecorrectionOnStart();
596c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
597c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
5984503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka        voiceIme.onStartInputView(inputView.getWindowToken());
599c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
600c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
601c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
602c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
603cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
604cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
605cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
6064b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
607c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
6080730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mShouldInsertMagicSpace = false;
609e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
6109fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
6111b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
6121b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
613dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
614cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
615cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
616cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // Make sure that passwords are not displayed in candidate view
617e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isPasswordInputType(inputType)
618e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
619cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
620cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
621e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)
622cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
6230730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = false;
624cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
6250730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = true;
626cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
627e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)) {
628cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
629cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
630cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
631cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
632cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
633cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
634cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
635cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
636cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
637e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
63836ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
639cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
640cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
641cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
642cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
643cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
644cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
645cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
646cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
647cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
648cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
649cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
650cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
651cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
652cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
653cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
654cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
659923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
660923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
661a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
662979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6631b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
664979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
665b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
666409220583333bdf06290dd9fd42f91b5c0d1b11asatok
6675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
668d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6694ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
670979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
671466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
672466741d8a78965b8509bf527344f289e50873092Mike LeBeau
673466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
6746495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
6756495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
6765a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
677d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
678d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
679d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
680d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
6816495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
6826495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
6836495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
684466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
685466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
686b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.showPunctuationHintIfNecessary();
687923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
688923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
689923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
690923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
691923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
694923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
695466741d8a78965b8509bf527344f289e50873092Mike LeBeau
696466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
697466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
698466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
699025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
700025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
701466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
702466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
703466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
704466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
705466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
706466741d8a78965b8509bf527344f289e50873092Mike LeBeau
707b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
7084f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
711025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
712025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
713025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
714f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (((mComposing.length() > 0 && mHasUncommittedTypedChars)
715b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                || mVoiceProxy.isVoiceInputHighlighted())
716025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                && (selectionChanged || candidatesCleared)) {
717025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            if (candidatesCleared) {
718025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // If the composing span has been cleared, save the typed word in the history for
719025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // recorrection before we reset the candidate strip.  Then, we'll be able to show
720025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // suggestions for recorrection right away.
721f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok                mRecorrection.saveRecorrectionSuggestion(mWord, mComposing);
722025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            }
723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
724f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
72589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (isCursorTouchingWord()) {
726cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.cancelUpdateBigramPredictions();
72789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.postUpdateSuggestions();
72889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            } else {
72989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                setPunctuationSuggestions();
73089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
732923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
736b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.setVoiceInputHighlighted(false);
737f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        } else if (!mHasUncommittedTypedChars && !mJustAccepted) {
738662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka            if (TextEntryState.isAcceptedDefault() || TextEntryState.isSpaceAfterPicked()) {
739662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                if (TextEntryState.isAcceptedDefault())
740662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                    TextEntryState.reset();
7410730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mJustAddedMagicSpace = false; // The user moved the cursor.
7429a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
744923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
745d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
746466741d8a78965b8509bf527344f289e50873092Mike LeBeau
747979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
748979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
749979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
750466741d8a78965b8509bf527344f289e50873092Mike LeBeau
7517a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.updateRecorrectionSelection(mKeyboardSwitcher,
7527a8dac55278cedd838be325f56b4c52d973c61f5satok                mCandidateView, candidatesStart, candidatesEnd, newSelStart,
7537a8dac55278cedd838be325f56b4c52d973c61f5satok                newSelEnd, oldSelStart, mLastSelectionStart,
7547a8dac55278cedd838be325f56b4c52d973c61f5satok                mLastSelectionEnd, mHasUncommittedTypedChars);
7557a8dac55278cedd838be325f56b4c52d973c61f5satok    }
7567a8dac55278cedd838be325f56b4c52d973c61f5satok
7577a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setLastSelection(int start, int end) {
7587a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionStart = start;
7597a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionEnd = end;
760923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
762c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
763c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
764c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
765c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
766c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
767c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
768c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
769c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
770c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
771c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
7727a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
773c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
774c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
775c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
776c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
777c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
778c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
779c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
780c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
781c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
782c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
783c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
784c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
785c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
786c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
787c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
7887a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
789c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
790c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
791c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
792c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
793923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
794923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
795979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
7961b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
797979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
7996e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8006e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8016e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8026e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
803b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
8049fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.clearWordsInHistory();
805923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
808923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8091b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
810979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
811a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
812bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
813bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
814bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
815bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8181b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8191b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8201b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
821b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
823923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
824a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8257e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8261b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8277e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8287e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
829979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
8307e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
831923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
832543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
836543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
8377a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        // TODO: Modify this if we support candidates with hard keyboard
838923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
8397a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final boolean shouldShowCandidates = shown
8407a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
8417a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (isExtractViewShown()) {
8427a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // No need to have extra space to show the key preview.
8437a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setMinimumHeight(0);
8447a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                super.setCandidatesViewShown(shown);
8457a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            } else {
8467a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // We must control the visibility of the suggestion strip in order to avoid clipped
8477a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // key previews, even when we don't show the suggestion strip.
8487a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
8497a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.INVISIBLE);
8507a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                super.setCandidatesViewShown(true);
8517a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            }
852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
854a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
856543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
857543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
858543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
859543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
860543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
8637a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        final KeyboardView inputView = mKeyboardSwitcher.getInputView();
86446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (inputView == null)
86546ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
86646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        final int containerHeight = mCandidateViewContainer.getHeight();
86746ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        int touchY = containerHeight;
8689e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
86946ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (mKeyboardSwitcher.isInputViewShown()) {
8707a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (mCandidateViewContainer.getVisibility() == View.VISIBLE) {
8717a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                touchY -= mCandidateStripHeight;
8729e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8737a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchWidth = inputView.getWidth();
8747a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchHeight = inputView.getHeight() + containerHeight
8757a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
8767a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
8779e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
8787a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
8797a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        + " height=" + touchHeight);
8809e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8817a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
8829e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
88346ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.contentTopInsets = touchY;
88446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.visibleTopInsets = touchY;
885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
886a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
887923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
888979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
889458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
890458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
891979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
892979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
893458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
894979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
895979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
896979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
897979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
898979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
900979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
901979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
904e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
905e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
906e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
9076e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
9086e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
909e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
910e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
916923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
917923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
918e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
919e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
920e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
921e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
922e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
923e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
924e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
925e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
926e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
927e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
928e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
929e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
930e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
931e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
932e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
933e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
934e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
936923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
939409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
940f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
941f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
943923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
946923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
948bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
954b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9561c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
957e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
958b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9591c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
960b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9611c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9621c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
963863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void swapSwapperAndSpace() {
964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
967863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
969863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                && lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
974b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9754ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
9764ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
9774ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
978863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void maybeDoubleSpace() {
979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
985571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
986fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE
987fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && mHandler.isAcceptingDoubleSpaces()) {
988fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.cancelDoubleSpacesTimer();
989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
993b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
994fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        } else {
995fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.startDoubleSpacesTimer();
996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
998a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
99941a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
100041a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
100141a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
100241a519729505a877844f2c57a33509c302dddbceKen Wakasa
100341a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
100441a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
100541a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10064ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1007571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1008571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
100941a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
101041a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
101141a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
101241a519729505a877844f2c57a33509c302dddbceKen Wakasa
10139a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
10149a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
10159a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
10169a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
10179a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10189a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1019571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
10209a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
10219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
10229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
10239a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
10266558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
10276558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1028d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1029923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1030923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1031923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1032923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1033923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1034923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1035923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1036923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1037923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1038923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1039a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1040e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
10419a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10422fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (!mConfigEnableShowSubtypeSettings) {
10432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                showSubtypeSelectorAndSettings();
10442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
10459a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
10469a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10479a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10489a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10499a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10509a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10519a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1052e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10539a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10549502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
105579efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10569a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10579a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10589a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10599a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10609a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10619a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10629a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
10639a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
10649a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10659a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10665f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
10675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
10688aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1070571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1072923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1073923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1074b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1075dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        final boolean accessibilityEnabled = switcher.isAccessibilityEnabled();
1076b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1078571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
10794189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
10804189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
10814189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
10824189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1083571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
10844189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1085dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette            if (!distinctMultiTouch || accessibilityEnabled)
1086b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
10874189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1088e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
10894189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1090dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette            if (!distinctMultiTouch || accessibilityEnabled)
1091b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
10924189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1093571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
10944189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
10954189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
10964189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
10974189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1098e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1099e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
11004189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1101e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1102e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
11034189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1104d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_NEXT_LANGUAGE:
110588fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(true);
11064189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1107d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_PREV_LANGUAGE:
110888fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(false);
11094189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1110571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1111b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
11124189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1113d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case Keyboard.CODE_SHORTCUT:
111420cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
11154189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1116571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
111745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
11184189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
11194189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
11204189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (isWordSeparator(primaryCode)) {
1121b5d17e52fcda39d540822e615bfb7ed5074e0034satok                handleSeparator(primaryCode, x, y);
11224189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
11238fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                handleCharacter(primaryCode, keyCodes, x, y);
11244189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
1125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1126b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1127dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1128dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1130a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11315a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11328aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1133b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.commitVoiceInput();
1134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
11369fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.abortRecorrection(false);
1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
113855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
113941a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1142b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11435f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
11440730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
1145dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11485a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11498aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
115083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11515f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
115283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
115383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1155b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.logAndRevertVoiceInput()) return;
11564f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1157504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1158504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1159979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1160979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1161b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleBackspace();
11624f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1163504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
1164f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
1171f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                    mHasUncommittedTypedChars = false;
1172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
117389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                if (1 == length) {
117489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // 1 == length means we are about to erase the last character of the word,
117589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // so we can show bigrams.
1176cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                    mHandler.postUpdateBigramPredictions();
117789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                } else {
117889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // length > 1, so we still have letters to deduce a suggestion from.
117989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    mHandler.postUpdateSuggestions();
118089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                }
1181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1187d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1188504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1190662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isUndoCommit()) {
1191923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1192979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1194504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1195504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1196504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1197dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
11996558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
12006558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
120155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
12026558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
12036558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
12046558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
12056558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
12066558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
12076558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
12086558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12106558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
12116558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12126558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1215979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
121845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
121945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
1220b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
1221b2707856aba4fc9b063f26305f1fb603b19c1701satok                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
122245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
122345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
122445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
122545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
122645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
122745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
122845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
122945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
123045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
123145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
1232b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
123345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
1234b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionNext(ic);
123545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
1236b2707856aba4fc9b063f26305f1fb603b19c1701satok        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
123745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
1238b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionPrevious(ic);
123945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
124045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
124145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
12428fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
1243b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleCharacter();
12444f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1245863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mJustAddedMagicSpace && isMagicSpaceStripper(primaryCode)) {
12460730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            removeTrailingSpace();
12470730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        }
12480730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard
1249863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mLastSelectionStart == mLastSelectionEnd) {
12509fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1251b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12524f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1253e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
12549fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
1255f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            if (!mHasUncommittedTypedChars) {
1256f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
1257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1258f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok                mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord);
1259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
12607e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
12631679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1264f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1265eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1266eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1267eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1268eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1269e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1270e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1271e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1272e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1273e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
127412a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
127512a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1276e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
12778aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
127812a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
127912a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1280979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1282f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1283f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1284f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
12850b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1287e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
12888fbd55229243cb66c03d5ea1f79dfb39f596590dsatok            mWord.add(code, keyCodes, x, y);
1289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
12911c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
12921c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1293b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
12941c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1297d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1299e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1301863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mJustAddedMagicSpace && isMagicSpaceSwapper(primaryCode)) {
1302863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            swapSwapperAndSpace();
1303863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        } else {
1304863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            mJustAddedMagicSpace = false;
1305863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1306863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1307b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1308979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
1309b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) code, isWordSeparator(code), x, y);
1310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1312b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private void handleSeparator(int primaryCode, int x, int y) {
1313b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleSeparator();
13144f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
131555b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
13166558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1317cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
13196558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
13206558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
13231b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
13269fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1328f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1330a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
13330730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            if (mAutoCorrectOn && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
1334b5d17e52fcda39d540822e615bfb7ed5074e0034satok                pickedDefault = pickDefaultSuggestion(primaryCode);
1335923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1337923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1338923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13394ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1340863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mJustAddedMagicSpace) {
1341863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            if (isMagicSpaceSwapper(primaryCode)) {
1342863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1343863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                swapSwapperAndSpace();
1344863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            } else {
1345863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                if (isMagicSpaceStripper(primaryCode)) removeTrailingSpace();
1346863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1347863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                mJustAddedMagicSpace = false;
1348863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            }
13490730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        } else {
13500730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendKeyChar((char)primaryCode);
13514ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13524ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1353863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1354863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            maybeDoubleSpace();
1355863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1356863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1357b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) primaryCode, true, x, y);
135889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1359979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
136055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
136155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
136255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
1363b2707856aba4fc9b063f26305f1fb603b19c1701satok                InputConnectionCompatUtils.commitCorrection(
136489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
136555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
136655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
136755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
136889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
136989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (Keyboard.CODE_SPACE == primaryCode) {
137089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isCursorTouchingWord()) {
137189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateSuggestions();
137289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateOldSuggestions();
1373cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.postUpdateBigramPredictions();
137489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
137589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
137689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Set punctuation right away. onUpdateSelection will fire but tests whether it is
137789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // already displayed or not, so it's okay.
137855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1380b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1383923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1385466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1388b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleClose();
1389923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
13901679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
13911679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
13921679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
13957a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isSuggestionsRequested() {
1396c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1397c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1399a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
14007a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingPunctuationList() {
14017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        return mSuggestPuncList == mCandidateView.getSuggestions();
14027599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14037599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14047a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingSuggestionsStrip() {
14057599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
14067599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
14077599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
14087599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14097599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14109fbfd5877305ed19a20663630b498b6b3fdae942satok    public boolean isCandidateStripVisible() {
1411b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1412b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1413952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
14149fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14159fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
14169fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
14179fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
14189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1422409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1423060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1424060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1425060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1426060efb6d82af1f896d90cb845c8ae07c726f85e1satok        View v = mKeyboardSwitcher.getInputView();
1427060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1428060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1429060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1430060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1431060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
14325a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1433060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1434060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1435060efb6d82af1f896d90cb845c8ae07c726f85e1satok        setCandidatesViewShown(isCandidateStripVisible());
1436060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1437060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1438466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1439466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1440409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14417e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1442466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1443466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14447e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1445b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.getAndResetIsShowingHint()) {
1446466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1447466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1448466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1449466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
14507e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
14519ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
14529ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
14539ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
14549ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1455466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1456466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1457466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1458409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
14609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1461b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                && !mVoiceProxy.isVoiceInputHighlighted()) {
1462923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1464466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1465f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
1466ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1468923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1469979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1470979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1471979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1472979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
14739f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: May need a better way of retrieving previous word
1474e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1475979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mWordSeparators);
14767e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
14779ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1478923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14796f99d12b0752ecdbceda7e5fddead214f939f533Tadashi G. Takaoka        boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
1480a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1481bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Here, we want to promote a whitelisted word if exists.
1482bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
1483bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
1484979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1485979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
14884a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1489979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1490952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        correctionAvailable &= !TextEntryState.isRecorrecting();
1491979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1492a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1493a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1494f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1495f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1496f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1497f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1498f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1499a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
15009fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
15019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
15029fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
15039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (previousSuggestions == mSuggestPuncList)
15049fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
15059fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
15069fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
15077e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1508979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
15094a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
15109fbfd5877305ed19a20663630b498b6b3fdae942satok    public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
15117e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
15127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
151314e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
151482411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
151582411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
15167e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1523ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1525923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1526b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private boolean pickDefaultSuggestion(int separatorCode) {
1527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1528d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1529d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15326780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1533b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord, separatorCode);
1534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
153555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
15369468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1537bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1538979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1539979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1541979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1542923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1544923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
15457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
1546b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
15474f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1548952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        final boolean recorrecting = TextEntryState.isRecorrecting();
15499a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
15509a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
15519a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
15529a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
15531b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
15541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
15551b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1556923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1557923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1558923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1562923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1563b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
15649a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15659a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
15669a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1567923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1568923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15696a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
15706a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
1571979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0))
1572979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || isSuggestedPunctuation(suggestion.charAt(0)))) {
1573979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1574979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1575979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
15767e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
1577863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // Find out whether the previous character is a space. If it is, as a special case
1578863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // for punctuation entered through the suggestion strip, it should be considered
1579863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a magic space even if it was a normal space. This is meant to help in case the user
1580863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // pressed space on purpose of displaying the suggestion strip punctuation.
158155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1582863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            final int toLeft = (ic == null) ? 0 : ic.getTextBeforeCursor(1, 0).charAt(0);
15834f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            final boolean oldMagicSpace = mJustAddedMagicSpace;
1584863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true;
1585a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1586a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1587a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
15884f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            mJustAddedMagicSpace = oldMagicSpace;
15899a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15909a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
15919a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
15926a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
15936a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
1594f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
159589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // If we are not composing a word, then it was a suggestion inferred from
159689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // context - no user input. We should reset the word composer.
159789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            mWord.reset();
159889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
15999a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
160055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
16019468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
16020c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1603bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1604979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1605bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToOnlyBigramDictionary(suggestion, 1);
16060c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1607979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
16087e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1609923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
16110730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        if (mShouldInsertMagicSpace && !recorrecting) {
16120730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendMagicSpace();
1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1614979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
16157f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We should show the hint if the user pressed the first entry AND either:
16167f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
16177f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        //   AND mHasDictionary is false)
16187f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
16197f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
16207f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
16217f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
16227f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
1623bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
1624bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                // If there is no dictionary the hint should be shown.
1625bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                && (!mHasDictionary
1626bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        // If "suggestion" is not in the dictionary, the hint should be shown.
1627bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        || !AutoCorrection.isValidWord(
1628bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                                mSuggest.getUnigramDictionaries(), suggestion, true));
1629b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1630952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!recorrecting) {
1631b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1632b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1633b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1634b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
1635b5d17e52fcda39d540822e615bfb7ed5074e0034satok                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
163689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // From there on onUpdateSelection() will fire so suggestions will be updated
1637b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        } else if (!showingAddToDictionaryHint) {
1638364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1639979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1640b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1641d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1642979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1643b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
164466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
164566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16469a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16479a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16489a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1649923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1650a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1651979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1652979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1653979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1654979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1655979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1656979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
165755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1658b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1659b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
16601679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1661923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1662923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1663b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.rememberReplacedWord(suggestion, mWordSeparators);
1664979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1665923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1666f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok        mRecorrection.saveRecorrectionSuggestion(mWord, suggestion);
1667f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
1668923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1669923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1670923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
167189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    private static final WordComposer sEmptyWordComposer = new WordComposer();
1672cb3320179d39a7983874697a0aa428b127675c9dJean Chalard    private void updateBigramPredictions() {
167389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (mSuggest == null || !isSuggestionsRequested())
167489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            return;
167589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1676cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        if (!mBigramPredictionEnabled) {
1677cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            setPunctuationSuggestions();
1678cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            return;
1679cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        }
1680cb3320179d39a7983874697a0aa428b127675c9dJean Chalard
168189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
168289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mWordSeparators);
168389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
168489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mKeyboardSwitcher.getInputView(), sEmptyWordComposer, prevWord);
168589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
168689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (builder.size() > 0) {
168789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Explicitly supply an empty typed word (the no-second-arg version of
168889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // showSuggestions will retrieve the word near the cursor, we don't want that here)
168989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            showSuggestions(builder.build(), "");
169089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
169189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isShowingPunctuationList()) setPunctuationSuggestions();
169289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
169389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    }
169489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
16957a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setPunctuationSuggestions() {
16967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(mSuggestPuncList);
16979fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
16986a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
16996a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1700bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) {
1701979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1702979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1703979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1704bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1705979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1706979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1707979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1708979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1709979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1710bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
1711979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1712979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1713bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            boolean selectedANotTypedWord) {
1714979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
1715bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
17160c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
17170c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
17180c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1719979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1720979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1721979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1722979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1723bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
1724bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean selectedATypedWordAndItsInAutoDic =
1725bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                !selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion);
1726bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean isValidWord = AutoCorrection.isValidWord(
1727bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), suggestion, true);
1728bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic
1729bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                || !isValidWord;
1730bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        if (needsToAddToAutoDictionary) {
1731e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1732e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1733979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1734e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1735863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // We don't want to register as bigrams words separated by a separator.
1736863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // For example "I will, and you too" : we don't want the pair ("will" "and") to be
1737863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a bigram.
1738e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1739863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                    mWordSeparators);
1740e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1741e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1742979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
174332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
174432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
174532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
17467a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isCursorTouchingWord() {
1747923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1748923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1749923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1750923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1751923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
175255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toLeft.charAt(0))
175355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toLeft.charAt(0))) {
1754923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1755923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1756a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
175755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toRight.charAt(0))
175855b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toRight.charAt(0))) {
1759923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1760923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1763a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1764dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1765dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1766dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1767dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1768dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1769923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1770923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
1771f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars && length > 0) {
1772923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1773504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1774923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1775923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1776504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1777504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
1778923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1780923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
178130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
178230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
178330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
178430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
178530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1786504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1787504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
178830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
1789b5d17e52fcda39d540822e615bfb7ed5074e0034satok                TextEntryState.typedCharacter(punctuation.charAt(0), true,
1790b5d17e52fcda39d540822e615bfb7ed5074e0034satok                        WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
179130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
179230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1793504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
1794f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
1795504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1796504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1797504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1798cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1799d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1800923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1805923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1808a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
1810923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
1811923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
1812923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1813923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1814863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private boolean isMagicSpaceStripper(int code) {
1815863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        return mMagicSpaceStrippers.contains(String.valueOf((char)code));
1816863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    }
1817863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1818863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private boolean isMagicSpaceSwapper(int code) {
1819863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        return mMagicSpaceSwappers.contains(String.valueOf((char)code));
1820923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18220730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private void sendMagicSpace() {
1823571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
18240730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = true;
1825b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1826923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1827923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1828923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
18290b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1831923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
183288fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
1833c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1834c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
18354ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1836cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
1837b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(),
1838b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.isVoiceButtonOnPrimary());
18390ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
18404b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
184136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
184236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
184388fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
184488fc9d44186120f9edc5cf7ec0e2af85260fed04satok    private void toggleLanguage(boolean next) {
184588fc9d44186120f9edc5cf7ec0e2af85260fed04satok        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
184688fc9d44186120f9edc5cf7ec0e2af85260fed04satok            mSubtypeSwitcher.toggleLanguage(next);
184788fc9d44186120f9edc5cf7ec0e2af85260fed04satok        }
184888fc9d44186120f9edc5cf7ec0e2af85260fed04satok        onRefreshKeyboard();// no need??
184988fc9d44186120f9edc5cf7ec0e2af85260fed04satok    }
185088fc9d44186120f9edc5cf7ec0e2af85260fed04satok
18515a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
18528aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
1853363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        if (mConfigSwipeDownDismissKeyboardEnabled)
1854363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1858e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPress(int primaryCode, boolean withSliding) {
1859cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1860cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1861cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1862cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
18631679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
18641679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1865571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1866e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onPressShift(withSliding);
1867e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
18686c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
186940a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
18706c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1871681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1872dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils.onPress(primaryCode, switcher);
1873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18755a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1876e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onRelease(int primaryCode, boolean withSliding) {
18771679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
18783f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
18791679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1880571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1881e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onReleaseShift(withSliding);
1882e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
18836c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
188440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1885dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils.onRelease(primaryCode, switcher);
1886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1887a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1888a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1889123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
1890923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1891923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1892923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1893123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
1894123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
1895123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
1896123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1897123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
1898123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
1899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1900923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
1903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
1904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1907923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
1908923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
1909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
1913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
1914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
1915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1916979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mKeyboardSwitcher.getInputView() != null) {
1917923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
1918923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1919923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSoundOn && !mSilentMode) {
1921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
1922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
1923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
1924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
1925571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
1926923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
1927923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1928571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
1929923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
1930923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1931571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
1932923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
1933923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1934923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
1936923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1939409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
1940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mVibrateOn) {
1941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
19431679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
19441679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
19451679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
1946979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
194766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
1948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
195171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public void promoteToUserDictionary(String word, int frequency) {
195234386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
195334386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
195434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
195534386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
195671c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
19576516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
19586516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
19596516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
196071c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public boolean getPopupOn() {
1961979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mPopupOn;
1962979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1963979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1964e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
19659f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: cleanup messy flags
1966e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
1967e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
1968e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                && !mInputTypeNoAutoCorrect && mHasDictionary;
196932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled)
1970e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
197132e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani                : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
1972979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mCorrectionMode = (mBigramSuggestionEnabled && mAutoCorrectOn && mAutoCorrectEnabled)
1973979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
1974e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
1975e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
1976e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
1977e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
1978e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
19790ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
198032e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
19815ef096f5f601c759e8a4a888aaca91ac5ccd9974Tadashi G. Takaoka        mSuggest.setQuickFixesEnabled(mQuickFixes
19824ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
198332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
198432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
19857599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private void updateSuggestionVisibility(SharedPreferences prefs) {
1986458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
19877599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
19889502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
1989458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
19907599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
1991458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
19927599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
19937599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
19947599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
19957599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
19967599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
19977599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1998466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
19999502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
2000466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2001466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2002bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
20039502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
2004bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2005bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2006507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
2007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2009466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2010923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2014507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private void loadSettings(EditorInfo attribute) {
2015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Get the settings preferences
201627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
2017699e429f1913197650cc2fc2d8cb6e506be66842satok        final boolean hasVibrator = VibratorCompatWrapper.getInstance(this).hasVibrator();
2018699e429f1913197650cc2fc2d8cb6e506be66842satok        mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
2019f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard        mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
2020f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard                mResources.getBoolean(R.bool.config_default_sound_enabled));
2021728115493e14f84d5f02a4812c8086a378813364Jean Chalard
2022728115493e14f84d5f02a4812c8086a378813364Jean Chalard        mPopupOn = isPopupEnabled(prefs);
20239502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
202489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
2025a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
202627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
202727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
2028b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard        mBigramPredictionEnabled = mBigramSuggestionEnabled && isBigramPredictionEnabled(prefs);
20291b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
2030466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2031b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.loadSettings(attribute, prefs);
2032409220583333bdf06290dd9fd42f91b5c0d1b11asatok
2033e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
20340ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
203527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        updateSuggestionVisibility(prefs);
203688fc9d44186120f9edc5cf7ec0e2af85260fed04satok
203788fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
203888fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.loadSettings();
203936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
204036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2041b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    /**
20421b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka     *  Load Auto correction threshold from SharedPreferences, and modify mSuggest's threshold.
2043b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda     */
20441b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private void loadAndSetAutoCorrectionThreshold(SharedPreferences sp) {
2045b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // When mSuggest is not initialized, cannnot modify mSuggest's threshold.
2046b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (mSuggest == null) return;
20471b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When auto correction setting is turned off, the threshold is ignored.
2048b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (!isAutoCorrectEnabled(sp)) return;
2049b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
20501b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
20511b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
20529ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
20531b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String[] autoCorrectionThresholdValues = mResources.getStringArray(
20549ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.array.auto_correction_threshold_values);
20551b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When autoCrrectionThreshold is greater than 1.0, auto correction is virtually turned off.
20561b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        double autoCorrectionThreshold = Double.MAX_VALUE;
2057b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        try {
20581b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
20591b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
20601b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                autoCorrectionThreshold = Double.parseDouble(
20611b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                        autoCorrectionThresholdValues[arrayIndex]);
2062b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda            }
2063b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        } catch (NumberFormatException e) {
20641b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            // Whenever the threshold settings are correct, never come here.
20651b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            autoCorrectionThreshold = Double.MAX_VALUE;
20661b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            Log.w(TAG, "Cannot load auto correction threshold setting."
20671b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
20681b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + ", autoCorrectionThresholdValues: "
20691b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + Arrays.toString(autoCorrectionThresholdValues));
2070b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        }
2071b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // TODO: This should be refactored :
20721b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        //           setAutoCorrectionThreshold should be called outside of this method.
20731b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
2074b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2075b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2076728115493e14f84d5f02a4812c8086a378813364Jean Chalard    private boolean isPopupEnabled(SharedPreferences sp) {
2077728115493e14f84d5f02a4812c8086a378813364Jean Chalard        final boolean showPopupOption = getResources().getBoolean(
2078728115493e14f84d5f02a4812c8086a378813364Jean Chalard                R.bool.config_enable_show_popup_on_keypress_option);
2079728115493e14f84d5f02a4812c8086a378813364Jean Chalard        if (!showPopupOption) return mResources.getBoolean(R.bool.config_default_popup_preview);
2080728115493e14f84d5f02a4812c8086a378813364Jean Chalard        return sp.getBoolean(Settings.PREF_POPUP_ON,
2081728115493e14f84d5f02a4812c8086a378813364Jean Chalard                mResources.getBoolean(R.bool.config_default_popup_preview));
2082728115493e14f84d5f02a4812c8086a378813364Jean Chalard    }
2083728115493e14f84d5f02a4812c8086a378813364Jean Chalard
208489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    private boolean isQuickFixesEnabled(SharedPreferences sp) {
208589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showQuickFixesOption = mResources.getBoolean(
208689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_quick_fixes_option);
208789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showQuickFixesOption) {
208889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
208989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
209089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
209189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_quick_fixes));
209289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    }
209389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard
2094b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
20951b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
20961b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
20979ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
20981b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String autoCorrectionOff = mResources.getString(
20999ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.string.auto_correction_threshold_mode_index_off);
21001b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
2101b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2102b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2103b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
210489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showBigramSuggestionsOption = mResources.getBoolean(
210589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_bigram_suggestions_option);
210689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showBigramSuggestionsOption) {
210789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
210889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
210989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
211089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_bigram_suggestions));
2111b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2112b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2113b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    private boolean isBigramPredictionEnabled(SharedPreferences sp) {
2114b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, mResources.getBoolean(
2115b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard                R.bool.config_default_bigram_prediction));
2116b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    }
2117b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard
21186a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
21197e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (mSuggestPuncs != null || mSuggestPuncList != null)
21207e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            return;
21217e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = new SuggestedWords.Builder();
21227e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        String puncs = mResources.getString(R.string.suggested_punctuations);
21237e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (puncs != null) {
21247e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            for (int i = 0; i < puncs.length(); i++) {
21257e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                builder.addWord(puncs.subSequence(i, i + 1));
21266a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
21276a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
21287e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncList = builder.build();
21297e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncs = puncs;
21306a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
21316a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2132979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSuggestedPunctuation(int code) {
2133979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestPuncs.contains(String.valueOf((char)code));
2134979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2135979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
21362fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
213785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
213885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
213985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
214085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
214185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
214285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
214385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
21442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
21452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
21462fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
21472fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
214885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
21492cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
21502cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
21512fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
21522fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
21532fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
21542fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2155aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2156aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2157aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
21582fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
21592fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
216085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
216185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
21622fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21642fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
216585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
216685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
216785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
216885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
216985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
217085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
21715a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
217585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2176ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
21772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
217885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2179ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
21802fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
218385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
218485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
21852fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
21862fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
218785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
218885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
218918e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        final IBinder windowToken = mKeyboardSwitcher.getInputView().getWindowToken();
219018e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        if (windowToken == null) return;
21912fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
21922fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
21932fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
21942fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
219585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
219685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2198a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2199923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
220118e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        lp.token = windowToken;
2202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22087e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
22097e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2211a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
22169fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
2218f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        p.println("  mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
2219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
22200730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        p.println("  mShouldInsertMagicSpace=" + mShouldInsertMagicSpace);
22211b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
2223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
2224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
2225979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        p.println("  mPopupOn=" + mPopupOn);
2226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
22276e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2229a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2232923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2233923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2234a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2239923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2246