LatinIME.java revision 309bff562fbaf47488e6bf6636840f00574187d8
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;
285a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
30571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
315a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
32de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
335a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
34388ce92ab8a635c5ad44620dad59baf05dfea510Amith Yamasani
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
4336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
46123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
4918e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasaimport android.os.IBinder;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
52bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
54e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
56979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
59923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
6066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
62e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.LayoutInflater;
63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
648e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
658e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
70466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
71466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedTextRequest;
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;
77466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.ArrayList;
78b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimodaimport java.util.Arrays;
79466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
80466741d8a78965b8509bf527344f289e50873092Mike LeBeau
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
8410dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatokpublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener {
858efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    private static final String TAG = LatinIME.class.getSimpleName();
86979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
87409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
88910b73127fa207dd26ec8124000262523b0aac0csatok    private static boolean DEBUG = LatinImeLogger.sDBG;
89a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
948efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     *
958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
9710dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok    @SuppressWarnings("dep-ann")
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
1008efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
1018efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
1028efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
1038efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
1048efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1074199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1084199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1094199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1104199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1114199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1128efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
113fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_SUGGESTIONS = 180;
114fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
115d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    private static final int DELAY_UPDATE_SHIFT_STATE = 300;
1169e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
117fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
121d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
122a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
123cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
124cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
125cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
126cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
127cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
128cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1377599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1387599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1397599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1407599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1417599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1427599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
143e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
1447a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka    private int mCandidateStripHeight;
145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1471b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
148a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
150a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
151610f1dc8553cf2ed97e763a06a19380c4a6cd636satok    private InputMethodManagerCompatWrapper mImm;
1522fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1532fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1542fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
15571c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1560ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
157b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    private VoiceProxy mVoiceProxy;
158a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
160979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1612bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1624ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
16336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
164c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
165c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mAutoSpace;
166c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
167c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
168c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
169c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
170dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette    private AccessibilityUtils mAccessibilityUtils;
171dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette
17271c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
1759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean mHasValidSuggestions;
176e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1779a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private boolean mJustAddedAutoSpace;
178e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
179952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa    private boolean mRecorrectionEnabled;
180b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    // Suggestion: use bigrams to adjust scores of suggestions obtained from unigram dictionary
181979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mBigramSuggestionEnabled;
182b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    // Prediction: use bigrams to predict the next word when there is no input for it yet
183b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    private boolean mBigramPredictionEnabled;
184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
187979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mPopupOn;
188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
1896e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
1902fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private boolean mConfigEnableShowSubtypeSettings;
191363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka    private boolean mConfigSwipeDownDismissKeyboardEnabled;
192de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
193de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDurationOfFadeoutLanguageOnSpacebar;
194d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka    private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
195fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka    private long mConfigDoubleSpacesTurnIntoPeriodTimeout;
196409220583333bdf06290dd9fd42f91b5c0d1b11asatok
19779efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
19879efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
19979efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
200979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
20179efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
20279efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
2037e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestPuncList;
204979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
209a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
2112296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
21271c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
215979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /* package */ String mWordSeparators;
216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mSentenceSeparators;
217979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private String mSuggestPuncs;
218b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    // TODO: Move this flag to VoiceProxy
21981c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
220466741d8a78965b8509bf527344f289e50873092Mike LeBeau
221cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
222cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private BroadcastReceiver mDictionaryPackInstallReceiver =
223cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard            new DictionaryPackInstallBroadcastReceiver(this);
224cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
225dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
226dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
227dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
22871c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
230071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka    public class WordAlternatives {
231071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        private final CharSequence mChosenWord;
232071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        private final WordComposer mWordComposer;
2334f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
234071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        public WordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
235979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mChosenWord = chosenWord;
236071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka            mWordComposer = wordComposer;
237979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
238979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
239979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getChosenWord() {
240979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord;
241979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
242979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
243071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        public CharSequence getOriginalWord() {
244071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka            return mWordComposer.getTypedWord();
245979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
246979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
247071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        public SuggestedWords.Builder getAlternatives() {
248071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka            return getTypedSuggestions(mWordComposer);
249979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
250979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
251979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
252071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        public int hashCode() {
253071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka            return mChosenWord.hashCode();
254979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
255979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
256979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
257071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        public boolean equals(Object o) {
258071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka            return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o);
259979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
260979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
26136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
262571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
263d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
264409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
267d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
268d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
269de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
270de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
271fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        private static final int MSG_SPACE_TYPED = 6;
272cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
273d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
277de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
279d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
280d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
283d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                setOldSuggestions();
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
286de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
288cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            case MSG_SET_BIGRAM_PREDICTIONS:
289cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                updateBigramPredictions();
29089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                break;
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
292b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.handleVoiceResults(preferCapitalization()
293de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
294de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
295de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
296de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
29766432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
298d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
29966432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
300de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
301de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        mConfigDurationOfFadeoutLanguageOnSpacebar);
302de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
303de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
304de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
30566432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
306d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), DELAY_UPDATE_SUGGESTIONS);
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
320d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
321d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
322d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
323d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
324d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
325d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
326d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
327d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                    DELAY_UPDATE_OLD_SUGGESTIONS);
328d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
329d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
330d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
331d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
332d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
333d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
334d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
335d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
336d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), DELAY_UPDATE_SHIFT_STATE);
337d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
338d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
339d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
340d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
341d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
342d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
343cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void postUpdateBigramPredictions() {
344cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
345cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS), DELAY_UPDATE_SUGGESTIONS);
34689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
34789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
348cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void cancelUpdateBigramPredictions() {
349cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
35089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
35189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
352d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
353d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
354d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
355de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
356d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
357de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
358de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
359de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
360de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
361050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
362c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The language is always displayed when the delay is negative.
363c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                final boolean needsToDisplayLanguage = localeChanged
364c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                        || mConfigDelayBeforeFadeoutLanguageOnSpacebar < 0;
365de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
366de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
367c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
368d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
369c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The fadeout animation will start when the delay is positive.
370d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
371de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
372de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                            mConfigDelayBeforeFadeoutLanguageOnSpacebar);
373de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
374de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
375de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
376fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
377fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void startDoubleSpacesTimer() {
378fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
379fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
380fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                    mConfigDoubleSpacesTurnIntoPeriodTimeout);
381fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
382fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
383fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void cancelDoubleSpacesTimer() {
384fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
385fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
386fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
387fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public boolean isAcceptingDoubleSpaces() {
388fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            return hasMessages(MSG_SPACE_TYPED);
389fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
390d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
391923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3927e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3937e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
39427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
39527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
39627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
3976d9021527a38ba1e94225020389621a0d7227aa1satok        LanguageSwitcherProxy.init(this, prefs);
39827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
39927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
400dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        AccessibilityUtils.init(this, prefs);
401363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
402923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
403363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
404610f1dc8553cf2ed97e763a06a19380c4a6cd636satok        mImm = InputMethodManagerCompatWrapper.getInstance(this);
4058efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
4060ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
4070ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
408dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils = AccessibilityUtils.getInstance();
409363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
410363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
411363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
412fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
413fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // If the option should not be shown, do not read the recorrection preference
414fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // but always use the default setting defined in the resources.
415fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
416952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
417f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard                    res.getBoolean(R.bool.config_default_recorrection_enabled));
418fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        } else {
419952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled);
420fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        }
421fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
4222fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mConfigEnableShowSubtypeSettings = res.getBoolean(
4232fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                R.bool.config_enable_show_subtype_settings);
424363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
425363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                R.bool.config_swipe_down_dismiss_keyboard_enabled);
426de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
427de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_delay_before_fadeout_language_on_spacebar);
428de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
429de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_duration_of_fadeout_language_on_spacebar);
430d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
43166432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
432fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        mConfigDoubleSpacesTurnIntoPeriodTimeout = res.getInteger(
433fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                R.integer.config_double_spaces_turn_into_period_timeout);
434979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4359502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
436979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
4379502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
438979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
4390ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
440979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
441979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
4429502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
443979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
444979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
445979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
446363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
4476a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
448b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
449cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Register to receive ringer mode change and network state change.
450cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Also receive installation and removal of a dictionary pack.
451123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
452123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
453123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
454923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
455b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
456cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
457cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final IntentFilter packageFilter = new IntentFilter();
458cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
459cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
460cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addDataScheme(SCHEME_PACKAGE);
461cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
462646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard
463646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        final IntentFilter newDictFilter = new IntentFilter();
464646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        newDictFilter.addAction(
465646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard                DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
466646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
46836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4690ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
470cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
471cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final Locale keyboardLocale = new Locale(localeStr);
47236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
473309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Resources res = mResources;
474309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
47536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
47636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
47736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
47827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
47989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
480979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4818efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
482cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
4831b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
48427023341658b4cf5430d18ddb94fd9502ecfe3cbTadashi G. Takaoka        updateAutoTextEnabled();
485e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
486cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserDictionary = new UserDictionary(this, localeStr);
487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
488e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
489e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4902bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
491e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
492cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO);
49334386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
494e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
495cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER);
496e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
497e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
498e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
499458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mWordSeparators = res.getString(R.string.word_separators);
500458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSentenceSeparators = res.getString(R.string.sentence_separators);
50136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
502309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        Utils.setSystemLocale(res, savedLocale);
503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
50436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
505cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /* package private */ void resetSuggestMainDict() {
506cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
507cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final Locale keyboardLocale = new Locale(localeStr);
508cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
509cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
510cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
511cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
512466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
513466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
514e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
515e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
516e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
517979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
519cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
520b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.destroy();
521979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
525923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
528dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
529b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
530b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
531466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
532466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
533466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
534b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
5352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
5362fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
537b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
5388b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
53981c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
541b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.onConfigurationChanged(conf);
54281c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
54388fc9d44186120f9edc5cf7ec0e2af85260fed04satok
54488fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
54588fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.onConfigurationChanged(conf);
546923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
547b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
549923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
5508d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
555e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
556e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
557e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
5587a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height);
559e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
562e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
563923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
564923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
565a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
566923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
56745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
56845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5698e09172df1bb176cc899940862c56bed9b9aec4esatok
57089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (DEBUG) {
571910b73127fa207dd26ec8124000262523b0aac0csatok            Log.d(TAG, "onStartInputView: " + inputView);
572910b73127fa207dd26ec8124000262523b0aac0csatok        }
573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
574979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
576923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
577923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5788d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5794ab730dbd34fad323063f2ffd31ce33de746668dsatok
580662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        TextEntryState.reset();
5816c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
582c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
583c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
584c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
585b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        final VoiceProxy voiceIme = mVoiceProxy;
586e9957752bcaad048746c7a57bbd2c0a59e1918a0satok        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(attribute.inputType)
587e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                || InputTypeCompatUtils.isVisiblePasswordInputType(attribute.inputType));
588c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
589cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
590c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
591c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
592c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
593c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
594c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHasValidSuggestions = false;
595c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
596c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mJustAddedAutoSpace = false;
597c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
598c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        loadSettings(attribute);
599c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
600cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            switcher.loadKeyboard(attribute,
6014503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    mSubtypeSwitcher.isShortcutImeEnabled() && voiceIme.isVoiceButtonEnabled(),
6024503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    voiceIme.isVoiceButtonOnPrimary());
603c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
604c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
605c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
6067a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(), false /* needsInputViewShown */ );
607c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
608c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
609c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
610c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
611c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
612dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        final boolean accessibilityEnabled = mAccessibilityUtils.isAccessibilityEnabled();
613dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette
614d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka        inputView.setKeyPreviewEnabled(mPopupOn);
615c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
616dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        inputView.setAccessibilityEnabled(accessibilityEnabled);
617c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
618952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        checkRecorrectionOnStart();
619c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
620c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
6214503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka        voiceIme.onStartInputView(inputView.getWindowToken());
622c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
623c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
624c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
625c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
626cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
627cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
628cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
6294b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
630c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
631c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mAutoSpace = false;
632e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
6339fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
6341b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
6351b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
636dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
637cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
638cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
639cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // Make sure that passwords are not displayed in candidate view
640e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isPasswordInputType(inputType)
641e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
642cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
643cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
644e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)
645cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
646cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mAutoSpace = false;
647cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
648cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mAutoSpace = true;
649cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
650e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)) {
651cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
652cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
653cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
654cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
655cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
656cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
657cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
658cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
659cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
660e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
66136ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
662cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
663cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
664cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
665cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
666cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
667cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
668cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
669cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
670cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
671cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
672cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
673cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
674cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
675cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
676cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
677cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
680923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
681952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa    private void checkRecorrectionOnStart() {
682952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!mRecorrectionEnabled) return;
683d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
684d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
685d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (ic == null) return;
686d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        // There could be a pending composing span.  Clean it up first.
687d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        ic.finishComposingText();
688d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
6899fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isShowingSuggestionsStrip() && isSuggestionsRequested()) {
690b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // First get the cursor position. This is required by setOldSuggestions(), so that
691b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // it can pass the correct range to setComposingRegion(). At this point, we don't
6924ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka            // have valid values for mLastSelectionStart/End because onUpdateSelection() has
693b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // not been called yet.
694b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedTextRequest etr = new ExtractedTextRequest();
695b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            etr.token = 0; // anything is fine here
696b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedText et = ic.getExtractedText(etr, 0);
697b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            if (et == null) return;
698b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
699b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionStart = et.startOffset + et.selectionStart;
700b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionEnd = et.startOffset + et.selectionEnd;
701b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
702b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // Then look for possible corrections in a delayed fashion
70355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) {
704d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateOldSuggestions();
70555b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            }
706b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani        }
707b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    }
708b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
712a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
713979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
7141b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
715979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
716b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
717409220583333bdf06290dd9fd42f91b5c0d1b11asatok
7185a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
719d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
7204ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
721979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
722466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
723466741d8a78965b8509bf527344f289e50873092Mike LeBeau
724466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
7256495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
7266495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
7275a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
728d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
729d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
730d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
731d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
7326495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
7336495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
7346495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
735466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
736466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
737b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.showPunctuationHintIfNecessary();
738923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
739923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
740923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
741923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
742923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
744923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
746466741d8a78965b8509bf527344f289e50873092Mike LeBeau
747466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
748466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
749466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
750025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
751025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
752466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
753466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
754466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
755466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
756466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
757466741d8a78965b8509bf527344f289e50873092Mike LeBeau
758b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
7594f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
760923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
762025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
763025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
764025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
765025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        if (((mComposing.length() > 0 && mHasValidSuggestions)
766b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                || mVoiceProxy.isVoiceInputHighlighted())
767025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                && (selectionChanged || candidatesCleared)) {
768025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            if (candidatesCleared) {
769025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // If the composing span has been cleared, save the typed word in the history for
770025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // recorrection before we reset the candidate strip.  Then, we'll be able to show
771025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // suggestions for recorrection right away.
772025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                saveWordInHistory(mComposing);
773025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            }
774923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
7759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
77689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (isCursorTouchingWord()) {
777cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.cancelUpdateBigramPredictions();
77889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.postUpdateSuggestions();
77989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            } else {
78089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                setPunctuationSuggestions();
78189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
782923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
783923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
784923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
785923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
786923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
787b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.setVoiceInputHighlighted(false);
7889fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (!mHasValidSuggestions && !mJustAccepted) {
789662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka            if (TextEntryState.isAcceptedDefault() || TextEntryState.isSpaceAfterPicked()) {
790662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                if (TextEntryState.isAcceptedDefault())
791662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                    TextEntryState.reset();
792e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mJustAddedAutoSpace = false; // The user moved the cursor.
7939a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
794923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
795923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
796d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
797466741d8a78965b8509bf527344f289e50873092Mike LeBeau
798979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
799979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
800979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
801466741d8a78965b8509bf527344f289e50873092Mike LeBeau
802952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mRecorrectionEnabled && isShowingSuggestionsStrip()) {
80366b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok            // Don't look for corrections if the keyboard is not visible
8041679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()) {
80566b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                // Check if we should go in or out of correction mode.
8066f99d12b0752ecdbceda7e5fddead214f939f533Tadashi G. Takaoka                if (isSuggestionsRequested()
80766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
808952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                                || TextEntryState.isRecorrecting())
8099fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                                && (newSelStart < newSelEnd - 1 || !mHasValidSuggestions)) {
81066b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
811cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                        mHandler.cancelUpdateBigramPredictions();
812d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                        mHandler.postUpdateOldSuggestions();
81366b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    } else {
814952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                        abortRecorrection(false);
81589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        // If showing the "touch again to save" hint, do not replace it. Else,
81689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        // show the bigrams if we are at the end of the text, punctuation otherwise.
81789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        if (mCandidateView != null
8187599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                                && !mCandidateView.isShowingAddToDictionaryHint()) {
81989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                            InputConnection ic = getCurrentInputConnection();
82089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                            if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) {
82189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                                if (!isShowingPunctuationList()) setPunctuationSuggestions();
82289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                            } else {
823cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                                mHandler.postUpdateBigramPredictions();
82489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                            }
82555b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        }
82666b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    }
827b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
828466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
829466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
831923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
832c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
833c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
834c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
835c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
836c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
837c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
838c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
839c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
840c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
841c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
842952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mRecorrectionEnabled && isSuggestionsRequested()) return;
843c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
844c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
845c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
846c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
847c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
848c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
849c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
850c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
851c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
852c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
853c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
854c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
855c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
856c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
857c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
858952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mRecorrectionEnabled && isSuggestionsRequested()) return;
859c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
860c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
861c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
862c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
865979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
8661b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
867979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
8696e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8706e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8716e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8726e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
873b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
874979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.clear();
875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
876923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
878923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8791b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
880979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
881a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
882bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
883bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
884bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
885bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
887923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8881b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8891b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8901b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
891b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
892923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
893923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
894a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8957e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8961b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8977e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8987e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
9007e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
902543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
906543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
9077a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        // TODO: Modify this if we support candidates with hard keyboard
908923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
9097a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final boolean shouldShowCandidates = shown
9107a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
9117a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (isExtractViewShown()) {
9127a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // No need to have extra space to show the key preview.
9137a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setMinimumHeight(0);
9147a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                super.setCandidatesViewShown(shown);
9157a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            } else {
9167a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // We must control the visibility of the suggestion strip in order to avoid clipped
9177a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // key previews, even when we don't show the suggestion strip.
9187a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
9197a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.INVISIBLE);
9207a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                super.setCandidatesViewShown(true);
9217a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            }
922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
924a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
926543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
927543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
928543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
929543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
930543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
931923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
932923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
9337a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        final KeyboardView inputView = mKeyboardSwitcher.getInputView();
93446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (inputView == null)
93546ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
93646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        final int containerHeight = mCandidateViewContainer.getHeight();
93746ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        int touchY = containerHeight;
9389e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
93946ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (mKeyboardSwitcher.isInputViewShown()) {
9407a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (mCandidateViewContainer.getVisibility() == View.VISIBLE) {
9417a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                touchY -= mCandidateStripHeight;
9429e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
9437a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchWidth = inputView.getWidth();
9447a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchHeight = inputView.getHeight() + containerHeight
9457a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
9467a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
9479e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
9487a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
9497a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        + " height=" + touchHeight);
9509e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
9517a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
9529e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
95346ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.contentTopInsets = touchY;
95446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.visibleTopInsets = touchY;
955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
956a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
958979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
959458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
960458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
961979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
962979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
963458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
964979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
965979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
966979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
967979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
968979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
969979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
970979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
971979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
974e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
975e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
976e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
9776e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
9786e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
979e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
980e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
985923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
986923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
987923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
988e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
989e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
990e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
991e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
992e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
993e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
994e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
995e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
996e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
997e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
998e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
999e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
1000e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
1001e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
1002e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
1003e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
1004e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
1005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
1007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1009409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
10109fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
10119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
1012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
1014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
1015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
1017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
1018bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
1019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1024b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
10261c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
1027e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
1028b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
10291c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
1030b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
10311c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
10321c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
1033923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void swapPunctuationAndSpace() {
1034923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1035923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1036923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
1037923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
1038571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastTwo.charAt(0) == Keyboard.CODE_SPACE
1039571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && isSentenceSeparator(lastTwo.charAt(1))) {
1040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
1043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1044b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10459a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1047923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
10481c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
10494ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    private void reswapPeriodAndSpace() {
10504ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        final InputConnection ic = getCurrentInputConnection();
10514ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (ic == null) return;
10524ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
10534ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastThree != null && lastThree.length() == 3
1054571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(0) == Keyboard.CODE_PERIOD
1055571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1056571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_PERIOD) {
10574ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.beginBatchEdit();
10584ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.deleteSurroundingText(3, 0);
10594ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.commitText(" ..", 1);
10604ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.endBatchEdit();
1061b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10624ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
10634ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
10644ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void doubleSpace() {
1066923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
1067923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1068923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
1070923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
1071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
1072571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1073fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE
1074fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && mHandler.isAcceptingDoubleSpaces()) {
1075fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.cancelDoubleSpacesTimer();
1076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1078923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1079923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1080b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10819a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1082fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        } else {
1083fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.startDoubleSpacesTimer();
1084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1085923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1086a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
108741a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
108841a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
108941a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
109041a519729505a877844f2c57a33509c302dddbceKen Wakasa
109141a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
109241a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
109341a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10944ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1095571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1096571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
109741a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
109841a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
109941a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
110041a519729505a877844f2c57a33509c302dddbceKen Wakasa
11019a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
11029a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
11039a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
11049a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
11059a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
11069a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1107571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
11089a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
11099a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
11109a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
11119a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
11146558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
11156558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1116d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1127a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1128e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
11299a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
11302fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (!mConfigEnableShowSubtypeSettings) {
11312fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                showSubtypeSelectorAndSettings();
11322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
11339a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
11349a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
11359a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
11369a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
11379a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
11389a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
11399a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1140e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
11419a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
11429502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
114379efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
11449a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
11459a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
11469a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
11479a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
11489a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
11499a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
11509a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
11519a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
11529a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
11539a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
11545f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
11555a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11568aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1158571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1162b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1163dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        final boolean accessibilityEnabled = switcher.isAccessibilityEnabled();
1164b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1166571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
11674189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
11684189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
11694189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
11704189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1171571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
11724189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1173dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette            if (!distinctMultiTouch || accessibilityEnabled)
1174b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
11754189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1176e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
11774189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1178dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette            if (!distinctMultiTouch || accessibilityEnabled)
1179b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
11804189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1181571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
11824189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
11834189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
11844189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11854189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1186e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1187e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
11884189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1189e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1190e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
11914189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1192d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_NEXT_LANGUAGE:
119388fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(true);
11944189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1195d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_PREV_LANGUAGE:
119688fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(false);
11974189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1198571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1199b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
12004189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1201d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case Keyboard.CODE_SHORTCUT:
120220cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
12034189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1204571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
120545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
12064189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
12074189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
1208571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (primaryCode != Keyboard.CODE_ENTER) {
12094189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                mJustAddedAutoSpace = false;
12104189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
12114189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (isWordSeparator(primaryCode)) {
1212b5d17e52fcda39d540822e615bfb7ed5074e0034satok                handleSeparator(primaryCode, x, y);
12134189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
12148fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                handleCharacter(primaryCode, keyCodes, x, y);
12154189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1217b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1218dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1219dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1221a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
12238aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1224b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.commitVoiceInput();
1225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1227952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        abortRecorrection(false);
1228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
122955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
123041a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1232923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1233b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
12345f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
12359a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAddedAutoSpace = false;
1236dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
12395a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
12408aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
124183e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
12425f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
124383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
124483e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1246b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.logAndRevertVoiceInput()) return;
12474f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1248504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1249504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1250979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1251979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1252b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleBackspace();
12534f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1254504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
12559fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1256923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
12629fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mHasValidSuggestions = false;
1263923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
126489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                if (1 == length) {
126589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // 1 == length means we are about to erase the last character of the word,
126689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // so we can show bigrams.
1267cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                    mHandler.postUpdateBigramPredictions();
126889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                } else {
126989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // length > 1, so we still have letters to deduce a suggestion from.
127089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    mHandler.postUpdateSuggestions();
127189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                }
1272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1278d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1279504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1281662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isUndoCommit()) {
1282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1283979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1285504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1286504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1287504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1288dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
12906558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
12916558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
129255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
12936558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
12946558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
12956558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
12966558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
12976558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
12986558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
12996558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
13016558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
13026558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
13036558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1306979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
130945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
131045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
1311b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
1312b2707856aba4fc9b063f26305f1fb603b19c1701satok                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
131345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
131445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
131545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
131645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
131745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
131845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
131945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
132045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
132145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
132245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
1323b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
132445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
1325b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionNext(ic);
132645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
1327b2707856aba4fc9b063f26305f1fb603b19c1701satok        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
132845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
1329b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionPrevious(ic);
133045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
133145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
133245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
1333952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa    private void abortRecorrection(boolean force) {
1334952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (force || TextEntryState.isRecorrecting()) {
1335952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            TextEntryState.onAbortRecorrection();
1336ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setCandidatesViewShown(isCandidateStripVisible());
1337979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            getCurrentInputConnection().finishComposingText();
1338b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1341a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
13428fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
1343b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleCharacter();
13444f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1345952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isRecorrecting()) {
1346952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            abortRecorrection(false);
1347b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
13484f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1349e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
13509fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
13519fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (!mHasValidSuggestions) {
13529fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mHasValidSuggestions = true;
1353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1354979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                saveWordInHistory(mBestWord);
1355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
13567e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13591679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1360f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1361eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1362eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1363eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1364eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1365e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1366e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1367e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1368e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1369e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
137012a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
137112a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1372e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
13738aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
137412a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
137512a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1376979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1377923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13789fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1379f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1380f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
13810b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1383e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
13848fbd55229243cb66c03d5ea1f79dfb39f596590dsatok            mWord.add(code, keyCodes, x, y);
1385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
13871c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
13881c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1389b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
13901c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1391923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1392923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1393d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1395e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1396923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1397b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1398979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
1399b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) code, isWordSeparator(code), x, y);
1400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1401923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1402b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private void handleSeparator(int primaryCode, int x, int y) {
1403b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleSeparator();
14044f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
140555b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
14066558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1407cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1408d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
14096558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
14106558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1412923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
14131b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1416952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            abortRecorrection(false);
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
14189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1420a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
14236f99d12b0752ecdbceda7e5fddead214f939f533Tadashi G. Takaoka            if (mAutoCorrectOn && primaryCode != '\'') {
1424b5d17e52fcda39d540822e615bfb7ed5074e0034satok                pickedDefault = pickDefaultSuggestion(primaryCode);
14259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // Picked the suggestion by the space key.  We consider this
14269a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // as "added an auto space".
1427571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                if (primaryCode == Keyboard.CODE_SPACE) {
14289a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                    mJustAddedAutoSpace = true;
14299a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                }
1430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1431923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1432923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1434571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (mJustAddedAutoSpace && primaryCode == Keyboard.CODE_ENTER) {
14359a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            removeTrailingSpace();
14369a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = false;
14379a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1438923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)primaryCode);
14394ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
14404ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // Handle the case of ". ." -> " .." with auto-space if necessary
14414ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // before changing the TextEntryState.
1442662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isPunctuationAfterAccepted() && primaryCode == Keyboard.CODE_PERIOD) {
14434ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            reswapPeriodAndSpace();
14444ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
14454ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1446b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) primaryCode, true, x, y);
144789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1448662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isPunctuationAfterAccepted() && primaryCode != Keyboard.CODE_ENTER) {
1449923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            swapPunctuationAndSpace();
14509fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            doubleSpace();
1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1453979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
145455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
145555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
145655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
1457b2707856aba4fc9b063f26305f1fb603b19c1701satok                InputConnectionCompatUtils.commitCorrection(
145889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
145955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
146055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
146155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
146289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
146389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (Keyboard.CODE_SPACE == primaryCode) {
146489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isCursorTouchingWord()) {
146589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateSuggestions();
146689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateOldSuggestions();
1467cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.postUpdateBigramPredictions();
146889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
146989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
147089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Set punctuation right away. onUpdateSelection will fire but tests whether it is
147189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // already displayed or not, so it's okay.
147255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1474b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1475923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1478923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1479466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1482b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleClose();
1483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
14841679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
14851679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
14861679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1489979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void saveWordInHistory(CharSequence result) {
1490979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mWord.size() <= 1) {
1491979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1492923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1493979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Skip if result is null. It happens in some edge case.
1494979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextUtils.isEmpty(result)) {
1495979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1497979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1498979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
1499979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final String resultCopy = result.toString();
1500071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka        WordAlternatives entry = new WordAlternatives(resultCopy,
1501979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                new WordComposer(mWord));
1502979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.add(entry);
1503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
15059fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isSuggestionsRequested() {
1506c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1507c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1509a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
15107599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private boolean isShowingPunctuationList() {
15117e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        return mSuggestPuncList == mCandidateView.getSuggestions();
15127599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
15137599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
15149fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isShowingSuggestionsStrip() {
15157599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
15167599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
15177599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
15187599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
15197599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCandidateStripVisible() {
1521b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1522b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1523952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
15249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
15259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
15269fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
15279fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
15289fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
15299fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1532409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1533060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1534060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1535060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1536060efb6d82af1f896d90cb845c8ae07c726f85e1satok        View v = mKeyboardSwitcher.getInputView();
1537060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1538060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1539060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1540060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1541060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
15425a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1543060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1544060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1545060efb6d82af1f896d90cb845c8ae07c726f85e1satok        setCandidatesViewShown(isCandidateStripVisible());
1546060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1547060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1548466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1549466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1550409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
15517e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1552466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1553466741d8a78965b8509bf527344f289e50873092Mike LeBeau
15547e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1555b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.getAndResetIsShowingHint()) {
1556466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1557466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1558466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1559466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
15607e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
15619ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
15629ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
15639ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
15649ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1565466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1566466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1567466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1568409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
15709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1571b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                && !mVoiceProxy.isVoiceInputHighlighted()) {
1572923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1574466741d8a78965b8509bf527344f289e50873092Mike LeBeau
15759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1576ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1577923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1579979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1580979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1581979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
15827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords.Builder getTypedSuggestions(WordComposer word) {
15839ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka        return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null);
1584979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1585979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1586979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showCorrections(WordAlternatives alternatives) {
15877e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = alternatives.getAlternatives();
15887e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
15897e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), alternatives.getOriginalWord());
1590979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1591979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1592979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
15939f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: May need a better way of retrieving previous word
1594e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1595979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mWordSeparators);
15967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
15979ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
15996f99d12b0752ecdbceda7e5fddead214f939f533Tadashi G. Takaoka        boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
1600a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1601bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Here, we want to promote a whitelisted word if exists.
1602bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
1603bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
1604979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1605979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1607923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16084a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1609979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1610952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        correctionAvailable &= !TextEntryState.isRecorrecting();
1611979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1612a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1613a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1614f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1615f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1616f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1617f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1618f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1619a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
16209fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
16219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
16229fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
16239fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (previousSuggestions == mSuggestPuncList)
16249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
16259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
16269fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
16277e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1628979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
16294a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
16307e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
16317e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
16327e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
163314e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
163482411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
163582411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
16367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1637923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1639923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1640923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1641923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1642923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1643ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1644923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1646b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private boolean pickDefaultSuggestion(int separatorCode) {
1647923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1648d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1649d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1650923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1651923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16526780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1653b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord, separatorCode);
1654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
165555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
16569468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1657bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1658979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1659979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1660923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1661979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1662923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1663923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1664923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
16657e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
1666b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
16674f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1668952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        final boolean recorrecting = TextEntryState.isRecorrecting();
16699a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
16709a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16719a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
16729a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
16731b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
16741b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
16751b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1680923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1681923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1682923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1683b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
16849a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16859a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16869a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1687923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1688923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16896a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
16906a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
1691979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0))
1692979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || isSuggestedPunctuation(suggestion.charAt(0)))) {
1693979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1694979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1695979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
16967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
169755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1698a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1699a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1700a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
17019a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
17029a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
17039a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
17046a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
17056a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
170689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (!mHasValidSuggestions) {
170789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // If we are not composing a word, then it was a suggestion inferred from
170889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // context - no user input. We should reset the word composer.
170989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            mWord.reset();
171089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
17119a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
171255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
17139468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
17140c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1715bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1716979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1717bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToOnlyBigramDictionary(suggestion, 1);
17180c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1719979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
17207e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1721923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1723952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mAutoSpace && !recorrecting) {
1724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendSpace();
17259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1726923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1727979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
17287f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We should show the hint if the user pressed the first entry AND either:
17297f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
17307f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        //   AND mHasDictionary is false)
17317f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
17327f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
17337f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
17347f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
17357f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
1736bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
1737bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                // If there is no dictionary the hint should be shown.
1738bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                && (!mHasDictionary
1739bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        // If "suggestion" is not in the dictionary, the hint should be shown.
1740bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        || !AutoCorrection.isValidWord(
1741bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                                mSuggest.getUnigramDictionaries(), suggestion, true));
1742b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1743952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!recorrecting) {
1744b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1745b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1746b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1747b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
1748b5d17e52fcda39d540822e615bfb7ed5074e0034satok                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
174989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // From there on onUpdateSelection() will fire so suggestions will be updated
1750b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        } else if (!showingAddToDictionaryHint) {
1751364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1752979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1753b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1754d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1755979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1756b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
175766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
175866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
17599a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
17609a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
17619a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1763a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1764979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1765979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1766979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1767979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1768979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1769979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
177055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1771b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1772b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
17731679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1774923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1775923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1776b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.rememberReplacedWord(suggestion, mWordSeparators);
1777979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1778923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1779979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        saveWordInHistory(suggestion);
17809fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mHasValidSuggestions = false;
1781923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1782923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1783923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1784b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    /**
1785b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * Tries to apply any typed alternatives for the word if we have any cached alternatives,
1786b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * otherwise tries to find new corrections and completions for the word.
1787b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @param touching The word that the cursor is touching, with position information
1788b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @return true if an alternative was found, false otherwise.
1789b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     */
1790e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) {
1791b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // If we didn't find a match, search for result in typed word history
1792b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordComposer foundWord = null;
1793b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordAlternatives alternatives = null;
1794bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Search old suggestions to suggest re-corrected suggestions.
1795b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        for (WordAlternatives entry : mWordHistory) {
1796e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
1797071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka                foundWord = entry.mWordComposer;
1798b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                alternatives = entry;
1799b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                break;
1800b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1801b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1802bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // If we didn't find a match, at least suggest corrections as re-corrected suggestions.
1803b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord == null
1804bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                && (AutoCorrection.isValidWord(
1805bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        mSuggest.getUnigramDictionaries(), touching.mWord, true))) {
1806b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            foundWord = new WordComposer();
1807e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            for (int i = 0; i < touching.mWord.length(); i++) {
1808e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                foundWord.add(touching.mWord.charAt(i), new int[] {
1809e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    touching.mWord.charAt(i)
18108fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1811b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1812e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
1813b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1814b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // Found a match, show suggestions
1815b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord != null || alternatives != null) {
1816b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (alternatives == null) {
1817071f47140cec02197de5e163f45c77990b39457dTadashi G. Takaoka                alternatives = new WordAlternatives(touching.mWord, foundWord);
1818b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1819b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            showCorrections(alternatives);
1820b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (foundWord != null) {
1821b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord = new WordComposer(foundWord);
1822b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            } else {
1823b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord.reset();
1824b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1825b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return true;
1826b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1827b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return false;
1828b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
1829b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1830979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void setOldSuggestions() {
18316f18a1fbcccf9cf5ca937b08098601a4fafead29satok        if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return;
1832b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setShowingVoiceSuggestions(false);
1833b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
1834b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return;
1835b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1836979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        InputConnection ic = getCurrentInputConnection();
1837979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (ic == null) return;
18389fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1839b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Extract the selected or touching text
1840e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
1841b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    mLastSelectionStart, mLastSelectionEnd, mWordSeparators);
1842979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1843e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (touching != null && touching.mWord.length() > 1) {
1844b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.beginBatchEdit();
1845979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1846b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                if (!mVoiceProxy.applyVoiceAlternatives(touching)
1847409220583333bdf06290dd9fd42f91b5c0d1b11asatok                        && !applyTypedAlternatives(touching)) {
1848952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                    abortRecorrection(true);
1849b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                } else {
1850952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                    TextEntryState.selectedForRecorrection();
18516f18a1fbcccf9cf5ca937b08098601a4fafead29satok                    InputConnectionCompatUtils.underlineWord(ic, touching);
1852979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
1853b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1854b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.endBatchEdit();
1855979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } else {
1856952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                abortRecorrection(true);
1857ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                setPunctuationSuggestions();  // Show the punctuation suggestions list
1858979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1859979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1860952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            abortRecorrection(true);
1861979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1862979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1863979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
186489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    private static final WordComposer sEmptyWordComposer = new WordComposer();
1865cb3320179d39a7983874697a0aa428b127675c9dJean Chalard    private void updateBigramPredictions() {
186689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (mSuggest == null || !isSuggestionsRequested())
186789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            return;
186889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1869cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        if (!mBigramPredictionEnabled) {
1870cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            setPunctuationSuggestions();
1871cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            return;
1872cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        }
1873cb3320179d39a7983874697a0aa428b127675c9dJean Chalard
187489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
187589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mWordSeparators);
187689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
187789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mKeyboardSwitcher.getInputView(), sEmptyWordComposer, prevWord);
187889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
187989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (builder.size() > 0) {
188089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Explicitly supply an empty typed word (the no-second-arg version of
188189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // showSuggestions will retrieve the word near the cursor, we don't want that here)
188289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            showSuggestions(builder.build(), "");
188389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
188489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isShowingPunctuationList()) setPunctuationSuggestions();
188589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
188689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    }
188789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1888ca26f20fa4903de46e374babbfba8c8a1a5cac93satok    private void setPunctuationSuggestions() {
18897e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(mSuggestPuncList);
18909fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
18916a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
18926a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1893bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) {
1894979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1895979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1896979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1897bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1898979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1900979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1901979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1902979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1903bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
1904979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1905979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1906bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            boolean selectedANotTypedWord) {
1907979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
1908bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
19090c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
19100c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
19110c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1912979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1913979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1914979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1915979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1916bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
1917bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean selectedATypedWordAndItsInAutoDic =
1918bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                !selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion);
1919bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean isValidWord = AutoCorrection.isValidWord(
1920bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), suggestion, true);
1921bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic
1922bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                || !isValidWord;
1923bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        if (needsToAddToAutoDictionary) {
1924e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1925e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1926979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1927e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1928e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1929e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    mSentenceSeparators);
1930e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1931e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1932979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
193332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
193432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
193532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
1936923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCursorTouchingWord() {
1937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
194255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toLeft.charAt(0))
194355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toLeft.charAt(0))) {
1944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1946a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
194755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toRight.charAt(0))
194855b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toRight.charAt(0))) {
1949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1953a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1954dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1955dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1956dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1957dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1958dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
19619fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions && length > 0) {
1962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1963504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1966504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1967504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
1968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
197130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
197230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
197330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
197430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
197530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1976504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1977504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
197830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
1979b5d17e52fcda39d540822e615bfb7ed5074e0034satok                TextEntryState.typedCharacter(punctuation.charAt(0), true,
1980b5d17e52fcda39d540822e615bfb7ed5074e0034satok                        WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
198130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
198230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1983504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
198430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mHasValidSuggestions = true;
1985504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1986504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1987504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1988cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1989d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1994923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1998a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
2000923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
2001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
2002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2003923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2004979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSentenceSeparator(int code) {
2005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mSentenceSeparators.contains(String.valueOf((char)code));
2006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void sendSpace() {
2009571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
2010b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
2011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
20140b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
2015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
201788fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
2018c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
2019c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
20204ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
2021cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
2022b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(),
2023b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.isVoiceButtonOnPrimary());
20240ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
20254b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
202636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
202736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
202888fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
202988fc9d44186120f9edc5cf7ec0e2af85260fed04satok    private void toggleLanguage(boolean next) {
203088fc9d44186120f9edc5cf7ec0e2af85260fed04satok        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
203188fc9d44186120f9edc5cf7ec0e2af85260fed04satok            mSubtypeSwitcher.toggleLanguage(next);
203288fc9d44186120f9edc5cf7ec0e2af85260fed04satok        }
203388fc9d44186120f9edc5cf7ec0e2af85260fed04satok        onRefreshKeyboard();// no need??
203488fc9d44186120f9edc5cf7ec0e2af85260fed04satok    }
203588fc9d44186120f9edc5cf7ec0e2af85260fed04satok
20365a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
20378aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
2038363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        if (mConfigSwipeDownDismissKeyboardEnabled)
2039363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
2040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20425a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
2043e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPress(int primaryCode, boolean withSliding) {
2044cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
2045cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
2046cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
2047cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
20481679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
20491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
2050571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
2051e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onPressShift(withSliding);
2052e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
20536c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
205440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
20556c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
2056681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
2057dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils.onPress(primaryCode, switcher);
2058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20605a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
2061e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onRelease(int primaryCode, boolean withSliding) {
20621679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
20633f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
20641679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
2065571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
2066e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onReleaseShift(withSliding);
2067e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
20686c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
206940a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
2070dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils.onRelease(primaryCode, switcher);
2071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2072a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2073a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2074123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
2075923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
2076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
2077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2078123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
2079123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
2080123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
2081123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
2082123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
2083123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
2084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2085923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
2086923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2087923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
2088923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
2089923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2090923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2092923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
2093923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
2094923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2095923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
2098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
2099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
2100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2101979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mKeyboardSwitcher.getInputView() != null) {
2102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
2103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSoundOn && !mSilentMode) {
2106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
2107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
2108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
2109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
2110571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
2111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
2112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2113571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
2114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
2115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2116571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
2117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
2118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
2121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2124409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
2125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mVibrateOn) {
2126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
2127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
21281679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
21291679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
21301679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
2131979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
213266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
2133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
213671c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public void promoteToUserDictionary(String word, int frequency) {
213734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
213834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
213934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
214034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
214171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
21426516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
21436516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
21446516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
214571c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public boolean getPopupOn() {
2146979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mPopupOn;
2147979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2148979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2149e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
21509f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: cleanup messy flags
2151e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
2152e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
2153e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                && !mInputTypeNoAutoCorrect && mHasDictionary;
215432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled)
2155e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
215632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani                : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
2157979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mCorrectionMode = (mBigramSuggestionEnabled && mAutoCorrectOn && mAutoCorrectEnabled)
2158979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2159e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2160e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2161e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2162e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2163e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
21640ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
216532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
21665ef096f5f601c759e8a4a888aaca91ac5ccd9974Tadashi G. Takaoka        mSuggest.setQuickFixesEnabled(mQuickFixes
21674ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
216832e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
216932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
21707599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private void updateSuggestionVisibility(SharedPreferences prefs) {
2171458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
21727599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
21739502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2174458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
21757599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2176458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
21777599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
21787599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
21797599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
21807599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
21817599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
21827599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2183466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
21849502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
2185466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2186466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2187bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
21889502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
2189bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2190bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2191507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
2192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2194466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2199507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private void loadSettings(EditorInfo attribute) {
2200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Get the settings preferences
220127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
2202699e429f1913197650cc2fc2d8cb6e506be66842satok        final boolean hasVibrator = VibratorCompatWrapper.getInstance(this).hasVibrator();
2203699e429f1913197650cc2fc2d8cb6e506be66842satok        mVibrateOn = hasVibrator && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
2204f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard        mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
2205f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard                mResources.getBoolean(R.bool.config_default_sound_enabled));
2206728115493e14f84d5f02a4812c8086a378813364Jean Chalard
2207728115493e14f84d5f02a4812c8086a378813364Jean Chalard        mPopupOn = isPopupEnabled(prefs);
22089502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
220989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
2210a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
221127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
221227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
2213b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard        mBigramPredictionEnabled = mBigramSuggestionEnabled && isBigramPredictionEnabled(prefs);
22141b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
2215466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2216b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.loadSettings(attribute, prefs);
2217409220583333bdf06290dd9fd42f91b5c0d1b11asatok
2218e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
22190ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
222027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        updateSuggestionVisibility(prefs);
222188fc9d44186120f9edc5cf7ec0e2af85260fed04satok
222288fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
222388fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.loadSettings();
222436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
222536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2226b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    /**
22271b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka     *  Load Auto correction threshold from SharedPreferences, and modify mSuggest's threshold.
2228b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda     */
22291b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private void loadAndSetAutoCorrectionThreshold(SharedPreferences sp) {
2230b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // When mSuggest is not initialized, cannnot modify mSuggest's threshold.
2231b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (mSuggest == null) return;
22321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When auto correction setting is turned off, the threshold is ignored.
2233b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (!isAutoCorrectEnabled(sp)) return;
2234b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
22351b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
22361b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
22379ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
22381b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String[] autoCorrectionThresholdValues = mResources.getStringArray(
22399ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.array.auto_correction_threshold_values);
22401b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When autoCrrectionThreshold is greater than 1.0, auto correction is virtually turned off.
22411b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        double autoCorrectionThreshold = Double.MAX_VALUE;
2242b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        try {
22431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
22441b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
22451b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                autoCorrectionThreshold = Double.parseDouble(
22461b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                        autoCorrectionThresholdValues[arrayIndex]);
2247b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda            }
2248b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        } catch (NumberFormatException e) {
22491b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            // Whenever the threshold settings are correct, never come here.
22501b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            autoCorrectionThreshold = Double.MAX_VALUE;
22511b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            Log.w(TAG, "Cannot load auto correction threshold setting."
22521b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
22531b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + ", autoCorrectionThresholdValues: "
22541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + Arrays.toString(autoCorrectionThresholdValues));
2255b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        }
2256b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // TODO: This should be refactored :
22571b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        //           setAutoCorrectionThreshold should be called outside of this method.
22581b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
2259b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2260b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2261728115493e14f84d5f02a4812c8086a378813364Jean Chalard    private boolean isPopupEnabled(SharedPreferences sp) {
2262728115493e14f84d5f02a4812c8086a378813364Jean Chalard        final boolean showPopupOption = getResources().getBoolean(
2263728115493e14f84d5f02a4812c8086a378813364Jean Chalard                R.bool.config_enable_show_popup_on_keypress_option);
2264728115493e14f84d5f02a4812c8086a378813364Jean Chalard        if (!showPopupOption) return mResources.getBoolean(R.bool.config_default_popup_preview);
2265728115493e14f84d5f02a4812c8086a378813364Jean Chalard        return sp.getBoolean(Settings.PREF_POPUP_ON,
2266728115493e14f84d5f02a4812c8086a378813364Jean Chalard                mResources.getBoolean(R.bool.config_default_popup_preview));
2267728115493e14f84d5f02a4812c8086a378813364Jean Chalard    }
2268728115493e14f84d5f02a4812c8086a378813364Jean Chalard
226989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    private boolean isQuickFixesEnabled(SharedPreferences sp) {
227089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showQuickFixesOption = mResources.getBoolean(
227189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_quick_fixes_option);
227289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showQuickFixesOption) {
227389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
227489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
227589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
227689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_quick_fixes));
227789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    }
227889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard
2279b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
22801b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
22811b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
22829ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
22831b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String autoCorrectionOff = mResources.getString(
22849ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.string.auto_correction_threshold_mode_index_off);
22851b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
2286b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2287b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2288b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
228989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showBigramSuggestionsOption = mResources.getBoolean(
229089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_bigram_suggestions_option);
229189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showBigramSuggestionsOption) {
229289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
229389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
229489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
229589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_bigram_suggestions));
2296b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2297b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2298b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    private boolean isBigramPredictionEnabled(SharedPreferences sp) {
2299b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, mResources.getBoolean(
2300b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard                R.bool.config_default_bigram_prediction));
2301b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard    }
2302b50591295d7c4ff7bb46ddf3e609d0046eb64d18Jean Chalard
23036a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
23047e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (mSuggestPuncs != null || mSuggestPuncList != null)
23057e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            return;
23067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = new SuggestedWords.Builder();
23077e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        String puncs = mResources.getString(R.string.suggested_punctuations);
23087e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (puncs != null) {
23097e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            for (int i = 0; i < puncs.length(); i++) {
23107e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                builder.addWord(puncs.subSequence(i, i + 1));
23116a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
23126a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
23137e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncList = builder.build();
23147e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncs = puncs;
23156a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
23166a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2317979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSuggestedPunctuation(int code) {
2318979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestPuncs.contains(String.valueOf((char)code));
2319979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2320979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
23212fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
232285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
232385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
232485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
232585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
232685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
232785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
232885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23292fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
23302fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
23312fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
23322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
233385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
23342cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
23352cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
23362fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
23372fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
23382fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
23392fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2340aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2341aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2342aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
23432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
23442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
234585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
234685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
23472fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
235085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
235185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
235285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
235385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
235485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
235585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23565a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2359923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
236085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2361ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
23622fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
236385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2364ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
23652fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
236885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
236985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
23702fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
23712fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
237285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
237385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
237418e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        final IBinder windowToken = mKeyboardSwitcher.getInputView().getWindowToken();
237518e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        if (windowToken == null) return;
23762fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
23772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
23782fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
23792fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
238085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
238185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2383a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
238618e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        lp.token = windowToken;
2387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2388923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2389923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2390923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2391923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2392923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23937e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
23947e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2395923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2396a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2399923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
24019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2402923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
24039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mHasValidSuggestions=" + mHasValidSuggestions);
2404923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
2405923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoSpace=" + mAutoSpace);
24061b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
2408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
2409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
2410979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        p.println("  mPopupOn=" + mPopupOn);
2411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
24126e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2414a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2419a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2426923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2427923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2431