LatinIME.java revision 7e99a28dfcc14f5b19220442db972ca8d786b4fe
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
195a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
205a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
21571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
23de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
245a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
259502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaokaimport com.android.inputmethod.latin.Utils.RingCharBuffer;
26409220583333bdf06290dd9fd42f91b5c0d1b11asatokimport com.android.inputmethod.voice.VoiceIMEConnector;
27388ce92ab8a635c5ad44620dad59baf05dfea510Amith Yamasani
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
3636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
39123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
4218e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasaimport android.os.IBinder;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
454174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasaimport android.os.Vibrator;
46bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
48e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
50979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
54e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.Gravity;
5566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
57e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.LayoutInflater;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
598e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
608e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
641b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaokaimport android.view.inputmethod.CorrectionInfo;
65923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
66466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
67466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedTextRequest;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputMethodManager;
700ed7191b4d1013a0b9d2fd1f26733dee7364871dsatokimport android.view.inputmethod.InputMethodSubtype;
719e347d3d448e48229c46aad394ec9bd60cd5807bsatokimport android.widget.FrameLayout;
72e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.HorizontalScrollView;
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 */
849a5d2ba03e7c8caf82cce64aa254d2177a72a8cfJean Chalardpublic class LatinIME extends InputMethodService 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     */
978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
1008efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
1018efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
1028efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
1038efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1074199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1084199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1094199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1104199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1118efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
112fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_SUGGESTIONS = 180;
113fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
114d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    private static final int DELAY_UPDATE_SHIFT_STATE = 300;
1159e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
116fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
120d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
121a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1227599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1237599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1247599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1257599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1287599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
136e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1391b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
140a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
142a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
14379efbed76f638be298493107fa2d0cd1b5eb529esatok    private InputMethodManager mImm;
1442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1462fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
14771c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1480ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
149409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private VoiceIMEConnector mVoiceConnector;
150a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
152979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1532bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1544ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
15536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
156c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
157c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mAutoSpace;
158c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
159c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
160c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
161c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
162dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette    private AccessibilityUtils mAccessibilityUtils;
163dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette
16471c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
1679fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean mHasValidSuggestions;
168e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1699a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private boolean mJustAddedAutoSpace;
170e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
171952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa    private boolean mRecorrectionEnabled;
172979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mBigramSuggestionEnabled;
173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
176979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mPopupOn;
177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
1786e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
1792fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private boolean mConfigEnableShowSubtypeSettings;
180363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka    private boolean mConfigSwipeDownDismissKeyboardEnabled;
181de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
182de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDurationOfFadeoutLanguageOnSpacebar;
183d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka    private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
184409220583333bdf06290dd9fd42f91b5c0d1b11asatok
18579efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
18679efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
18779efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
188979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
18979efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
19079efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
1917e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestPuncList;
192979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
195c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa    private boolean mJustReverted;
196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
198a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
199923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
2002296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
20171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
204979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /* package */ String mWordSeparators;
205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mSentenceSeparators;
206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private String mSuggestPuncs;
207409220583333bdf06290dd9fd42f91b5c0d1b11asatok    // TODO: Move this flag to VoiceIMEConnector
20881c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
209466741d8a78965b8509bf527344f289e50873092Mike LeBeau
210dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
211dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
212dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
21371c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
214979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
215979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public abstract static class WordAlternatives {
216979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        protected CharSequence mChosenWord;
2174f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
218979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives() {
219979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
221979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
222979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives(CharSequence chosenWord) {
223979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mChosenWord = chosenWord;
224979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
225979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
226979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
227979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public int hashCode() {
228979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord.hashCode();
229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
230979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
231979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public abstract CharSequence getOriginalWord();
232979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
233979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getChosenWord() {
234979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord;
235979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
236979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2377e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public abstract SuggestedWords.Builder getAlternatives();
238979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
239979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
240979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public class TypedWordAlternatives extends WordAlternatives {
241979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        private WordComposer word;
242979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
243979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives() {
244979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
245979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
246979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
247979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
248979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            super(chosenWord);
249979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            word = wordComposer;
250979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
251979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
252979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
253979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getOriginalWord() {
254979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return word.getTypedWord();
255979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
256979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
257979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
2587e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public SuggestedWords.Builder getAlternatives() {
259979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return getTypedSuggestions(word);
260979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
261979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
26236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
263571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
264d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
265409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
267d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
268d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
269d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
270de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
271de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
272d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
275de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
278d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
279d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
280d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                setOldSuggestions();
283d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
285de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
288e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mVoiceConnector.handleVoiceResults(preferCapitalization()
289de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
290de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
291de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
292de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
29366432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
294d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
29566432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
296de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
297de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        mConfigDurationOfFadeoutLanguageOnSpacebar);
298de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
299de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
300de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
30166432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
302d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
306d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
309d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), DELAY_UPDATE_SUGGESTIONS);
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
320d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
321d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
322d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
323d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                    DELAY_UPDATE_OLD_SUGGESTIONS);
324d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
325d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
326d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
327d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
328d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
329d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
330d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
331d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
332d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), DELAY_UPDATE_SHIFT_STATE);
333d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
334d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
335d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
336d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
337d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
338d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
339d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
340d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
341d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
342de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
343d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
344de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
345de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
346de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
347de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
348050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
349de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
350de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
351d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
352d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
353de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is always displayed when the delay is negative.
354d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
355de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
356de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                            mConfigDelayBeforeFadeoutLanguageOnSpacebar);
357de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
358de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
359de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
360d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
361923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3627e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3637e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
36427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
36527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
36627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
36727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
36827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
369dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        AccessibilityUtils.init(this, prefs);
370363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
371923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
372363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
37379efbed76f638be298493107fa2d0cd1b5eb529esatok        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
3748efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
3750ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3760ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
377dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils = AccessibilityUtils.getInstance();
378363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
379363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
380363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
381fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
382fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // If the option should not be shown, do not read the recorrection preference
383fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // but always use the default setting defined in the resources.
384fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
385952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
386f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard                    res.getBoolean(R.bool.config_default_recorrection_enabled));
387fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        } else {
388952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            mRecorrectionEnabled = res.getBoolean(R.bool.config_default_recorrection_enabled);
389fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        }
390fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
3912fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mConfigEnableShowSubtypeSettings = res.getBoolean(
3922fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                R.bool.config_enable_show_subtype_settings);
393363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
394363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                R.bool.config_swipe_down_dismiss_keyboard_enabled);
395de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
396de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_delay_before_fadeout_language_on_spacebar);
397de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
398de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_duration_of_fadeout_language_on_spacebar);
399d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
40066432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
401979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4029502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
403979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
4049502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
405979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
4060ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
407979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
408979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
4099502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
410979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
411979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
412979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
413363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
4146a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
415b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
416123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        // register to receive ringer mode change and network state change.
417123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
418123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
419123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
42127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
42336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4240ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
4254ab730dbd34fad323063f2ffd31ce33de746668dsatok        String locale = mSubtypeSwitcher.getInputLocaleStr();
42636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4270ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
42836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
42936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
43036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
43127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
43289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
433979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
434458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
4358efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
436458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSuggest = new Suggest(this, mainDicResId);
4371b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
43827023341658b4cf5430d18ddb94fd9502ecfe3cbTadashi G. Takaoka        updateAutoTextEnabled();
439e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
4400ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mUserDictionary = new UserDictionary(this, locale);
441923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
442e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
443e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4442bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
445e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
446e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
44734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
448e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
449e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
450e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
451e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
452e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
453458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mWordSeparators = res.getString(R.string.word_separators);
454458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSentenceSeparators = res.getString(R.string.sentence_separators);
45536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4560ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.changeSystemLocale(savedLocale);
457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
45836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
459466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
460466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
461e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
462e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
463e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
464979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
465923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
466409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.destroy();
467979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
468979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
469923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
470923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
471923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
472923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
474dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
475b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
476b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
477466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
478466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
479466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
480b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
4812fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
4822fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
483b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
4848b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
48581c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
487bbd651a00898dabf6b2ae0e715d99953ea81063fLuca Zanolin        mVoiceConnector.onConfigurationChanged(conf);
48881c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
490b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
492923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
4938d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
494923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
498e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
499e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
500e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
501e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (container.getPaddingRight() != 0) {
502e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            HorizontalScrollView scrollView =
503e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                    (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view);
504e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
505e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            container.setGravity(Gravity.CENTER_HORIZONTAL);
506e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
507e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
509923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
510e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
511923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
513a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
514923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
51545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
51645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5178e09172df1bb176cc899940862c56bed9b9aec4esatok
518910b73127fa207dd26ec8124000262523b0aac0csatok        if(DEBUG) {
519910b73127fa207dd26ec8124000262523b0aac0csatok            Log.d(TAG, "onStartInputView: " + inputView);
520910b73127fa207dd26ec8124000262523b0aac0csatok        }
521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
525923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5268d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5274ab730dbd34fad323063f2ffd31ce33de746668dsatok
528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.newSession(this);
5296c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
530c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
531c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
532c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
5334b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mVoiceConnector.resetVoiceStates(Utils.isPasswordInputType(attribute.inputType)
5344b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka                || Utils.isVisiblePasswordInputType(attribute.inputType));
535c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
536cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
537c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
538c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
539c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
540c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
541c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHasValidSuggestions = false;
542c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
543c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mJustAddedAutoSpace = false;
544c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
545c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        loadSettings(attribute);
546c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
547cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            switcher.loadKeyboard(attribute,
548c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonEnabled(),
549c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonOnPrimary());
550c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
551c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
552c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
553c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(),
554c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                false /* needsInputViewShown */ );
555c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
556c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
557c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
558c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
559c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
560dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        final boolean accessibilityEnabled = mAccessibilityUtils.isAccessibilityEnabled();
561dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette
562c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setPreviewEnabled(mPopupOn);
563c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
564dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        inputView.setAccessibilityEnabled(accessibilityEnabled);
565c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
566952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        checkRecorrectionOnStart();
567c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
568c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
569c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.onStartInputView(inputView.getWindowToken());
570c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
571c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
572c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
573c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
574cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
575cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
576cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
5774b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
578c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
579c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mAutoSpace = false;
580e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
5819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
5821b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
5831b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
584dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
585cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
586cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
587cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // Make sure that passwords are not displayed in candidate view
588cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if (Utils.isPasswordInputType(inputType)
589cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || Utils.isVisiblePasswordInputType(inputType)) {
590cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
591cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
592cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if (Utils.isEmailVariation(variation)
593cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
594cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mAutoSpace = false;
595cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
596cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mAutoSpace = true;
597cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
598cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if (Utils.isEmailVariation(variation)) {
599cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
600cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
601cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
602cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
603cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
604cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
605cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
606cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
607cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
608e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
60936ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
610cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
611cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
612cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
613cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
614cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
615cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
616cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
617cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
618cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
619cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
620cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
621cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
622cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
623cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
624cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
625cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
626923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
627923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
628923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
629952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa    private void checkRecorrectionOnStart() {
630952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!mRecorrectionEnabled) return;
631d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
632d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
633d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (ic == null) return;
634d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        // There could be a pending composing span.  Clean it up first.
635d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        ic.finishComposingText();
636d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
6379fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isShowingSuggestionsStrip() && isSuggestionsRequested()) {
638b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // First get the cursor position. This is required by setOldSuggestions(), so that
639b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // it can pass the correct range to setComposingRegion(). At this point, we don't
6404ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka            // have valid values for mLastSelectionStart/End because onUpdateSelection() has
641b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // not been called yet.
642b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedTextRequest etr = new ExtractedTextRequest();
643b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            etr.token = 0; // anything is fine here
644b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedText et = ic.getExtractedText(etr, 0);
645b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            if (et == null) return;
646b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
647b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionStart = et.startOffset + et.selectionStart;
648b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionEnd = et.startOffset + et.selectionEnd;
649b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
650b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // Then look for possible corrections in a delayed fashion
65155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) {
652d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateOldSuggestions();
65355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            }
654b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani        }
655b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    }
656b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
659923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
660a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
661979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6621b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
663979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
664409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
665409220583333bdf06290dd9fd42f91b5c0d1b11asatok
6665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
667d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6684ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
669979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
670466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
671466741d8a78965b8509bf527344f289e50873092Mike LeBeau
672466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
6736495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
6746495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
6755a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
676d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
677d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
678d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
679d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
6806495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
6816495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
6826495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
683466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
684466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
685409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.showPunctuationHintIfNecessary();
686923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
687923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
688923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
689923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
690923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
691923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
694466741d8a78965b8509bf527344f289e50873092Mike LeBeau
695466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
696466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
697466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
698025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
699025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
700466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
701466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
702466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
703466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
704466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
705466741d8a78965b8509bf527344f289e50873092Mike LeBeau
706409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setCursorAndSelection(newSelEnd, newSelStart);
7074f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
710025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
711025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
712025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
713025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        if (((mComposing.length() > 0 && mHasValidSuggestions)
714025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || mVoiceConnector.isVoiceInputHighlighted())
715025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                && (selectionChanged || candidatesCleared)) {
716025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            if (candidatesCleared) {
717025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // If the composing span has been cleared, save the typed word in the history for
718025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // recorrection before we reset the candidate strip.  Then, we'll be able to show
719025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // suggestions for recorrection right away.
720025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                saveWordInHistory(mComposing);
721025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            }
722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
7239fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
724d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
725923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
726923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
727923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
728923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
729923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
730409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.setVoiceInputHighlighted(false);
7319fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (!mHasValidSuggestions && !mJustAccepted) {
7329a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            switch (TextEntryState.getState()) {
733e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case ACCEPTED_DEFAULT:
734e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                TextEntryState.reset();
735e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                // $FALL-THROUGH$
736e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case SPACE_AFTER_PICKED:
737e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mJustAddedAutoSpace = false; // The user moved the cursor.
738e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
739e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            default:
740e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
7419a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
742923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
744d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
745466741d8a78965b8509bf527344f289e50873092Mike LeBeau
746979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
747979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
748979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
749466741d8a78965b8509bf527344f289e50873092Mike LeBeau
750952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mRecorrectionEnabled && isShowingSuggestionsStrip()) {
75166b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok            // Don't look for corrections if the keyboard is not visible
7521679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()) {
75366b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                // Check if we should go in or out of correction mode.
7549fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                if (isSuggestionsRequested() && !mJustReverted
75566b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
756952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                                || TextEntryState.isRecorrecting())
7579fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                                && (newSelStart < newSelEnd - 1 || !mHasValidSuggestions)) {
75866b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
759d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                        mHandler.postUpdateOldSuggestions();
76066b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    } else {
761952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                        abortRecorrection(false);
76255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        // Show the punctuation suggestions list if the current one is not
763364da8c618303a7764595d2c15ee034a7671365dKen Wakasa                        // and if not showing "Touch again to save".
7647599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        if (mCandidateView != null && !isShowingPunctuationList()
7657599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                                && !mCandidateView.isShowingAddToDictionaryHint()) {
766ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                            setPunctuationSuggestions();
76755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        }
76866b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    }
769b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
770466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
771466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
772923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
773923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
774c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
775c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
776c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
777c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
778c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
779c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
780c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
781c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
782c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
783c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
784952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mRecorrectionEnabled && isSuggestionsRequested()) return;
785c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
786c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
787c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
788c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
789c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
790c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
791c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
792c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
793c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
794c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
795c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
796c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
797c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
798c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
799c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
800952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mRecorrectionEnabled && isSuggestionsRequested()) return;
801c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
802c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
803c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
804c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
805923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
807979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
8081b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
809979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
810923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
8116e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8126e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8136e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8146e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
815409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.hideVoiceWindow(mConfigurationChanging);
816979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.clear();
817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
819923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
820923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8221b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
823979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
824a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
8251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int count = (applicationSpecifiedCompletions != null)
8261b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    ? applicationSpecifiedCompletions.length : 0;
8271b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            for (int i = 0; i < count; i++) {
828a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
829923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8311b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8331b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
834b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
837a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8387e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8391b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8407e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8417e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
842979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
8437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
845543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
849543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // TODO: Remove this if we support candidates with hard keyboard
851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
8521679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            super.setCandidatesViewShown(shown
8531679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true));
854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
856a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
858543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
859543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
860543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
861543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
862543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
865264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        if (!isFullscreenMode()) {
866264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project            outInsets.contentTopInsets = outInsets.visibleTopInsets;
867264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        }
8689e347d3d448e48229c46aad394ec9bd60cd5807bsatok        KeyboardView inputView = mKeyboardSwitcher.getInputView();
8699e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
8709e347d3d448e48229c46aad394ec9bd60cd5807bsatok        if (inputView != null && mKeyboardSwitcher.isInputViewShown()) {
8719e347d3d448e48229c46aad394ec9bd60cd5807bsatok            final int x = 0;
8729e347d3d448e48229c46aad394ec9bd60cd5807bsatok            int y = 0;
8739e347d3d448e48229c46aad394ec9bd60cd5807bsatok            final int width = inputView.getWidth();
8749e347d3d448e48229c46aad394ec9bd60cd5807bsatok            int height = inputView.getHeight() + EXTENDED_TOUCHABLE_REGION_HEIGHT;
8759e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (mCandidateViewContainer != null) {
8769e347d3d448e48229c46aad394ec9bd60cd5807bsatok                ViewParent candidateParent = mCandidateViewContainer.getParent();
8779e347d3d448e48229c46aad394ec9bd60cd5807bsatok                if (candidateParent instanceof FrameLayout) {
87800eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                    FrameLayout fl = (FrameLayout) candidateParent;
87900eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                    if (fl != null) {
88000eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        // Check frame layout's visibility
88100eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        if (fl.getVisibility() == View.INVISIBLE) {
88200eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                            y = fl.getHeight();
88300eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                            height += y;
88400eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        } else if (fl.getVisibility() == View.VISIBLE) {
88500eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                            height += fl.getHeight();
88600eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        }
8879e347d3d448e48229c46aad394ec9bd60cd5807bsatok                    }
8889e347d3d448e48229c46aad394ec9bd60cd5807bsatok                }
8899e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8909e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
8919e347d3d448e48229c46aad394ec9bd60cd5807bsatok                Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height);
8929e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8936845da8d7b940018c4ef77646f0028d131ed2753satok            outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
8949e347d3d448e48229c46aad394ec9bd60cd5807bsatok            outInsets.touchableRegion.set(x, y, width, height);
8959e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
896923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
897a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
900458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
901458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
902979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
903979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
904458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
905979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
906979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
907979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
908979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
909979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
910979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
911979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
912979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
915e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
916e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
917e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
9186e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
9196e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
920e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
921e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
926923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
927923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
928923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
929e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
930e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
931e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
932e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
933e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
934e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
935e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
936e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
937e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
938e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
939e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
940e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
941e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
942e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
943e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
944e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
945e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
946923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
950409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
9519fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
9529fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
959979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
963923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
965b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9671c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
968e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
969b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9701c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
971b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9721c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9731c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void swapPunctuationAndSpace() {
975923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
979571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastTwo.charAt(0) == Keyboard.CODE_SPACE
980571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && isSentenceSeparator(lastTwo.charAt(1))) {
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
985b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9869a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
987923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
9891c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
9904ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    private void reswapPeriodAndSpace() {
9914ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        final InputConnection ic = getCurrentInputConnection();
9924ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (ic == null) return;
9934ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
9944ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastThree != null && lastThree.length() == 3
995571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(0) == Keyboard.CODE_PERIOD
996571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
997571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_PERIOD) {
9984ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.beginBatchEdit();
9994ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.deleteSurroundingText(3, 0);
10004ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.commitText(" ..", 1);
10014ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.endBatchEdit();
1002b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10034ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
10044ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
10054ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void doubleSpace() {
1007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //if (!mAutoPunctuate) return;
1008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
1009923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1010923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
1012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
1014571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1015571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1020b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1024a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
102541a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
102641a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
102741a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
102841a519729505a877844f2c57a33509c302dddbceKen Wakasa
102941a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
103041a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
103141a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10324ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1033571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1034571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
103541a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
103641a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
103741a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
103841a519729505a877844f2c57a33509c302dddbceKen Wakasa
10399a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
10409a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
10419a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
10429a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
10439a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10449a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1045571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
10469a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
10479a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
10489a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
10499a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1050923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1051923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
10526558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
10536558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1054d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1055923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1060923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1061923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1062923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1063923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1065a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1066e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
10679a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (!mConfigEnableShowSubtypeSettings) {
10692fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                showSubtypeSelectorAndSettings();
10702fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
10719a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
10729a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10739a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10749a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10759a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10769a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10779a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1078e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10799a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10809502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
108179efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10829a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10839a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10849a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10859a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10869a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10879a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10889a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
10899a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
10909a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10919a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10925f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
10935a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
10948aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1095923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1096571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1100b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1101dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        final boolean accessibilityEnabled = switcher.isAccessibilityEnabled();
1102b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1104571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
11054189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
11064189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
11074189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
11084189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1109571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
11104189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1111dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette            if (!distinctMultiTouch || accessibilityEnabled)
1112b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
11134189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1114e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
11154189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1116dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette            if (!distinctMultiTouch || accessibilityEnabled)
1117b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
11184189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1119571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
11204189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
11214189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
11224189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11234189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1124e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1125e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
11264189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1127e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1128e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
11294189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1130571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_NEXT_LANGUAGE:
11314189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, true);
11324189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1133571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_PREV_LANGUAGE:
11344189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, false);
11354189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1136571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1137b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
11384189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
113920cdb37bd062ae6cb6d42ad6229a19733476cd55satok        case Keyboard.CODE_VOICE:
114020cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
11414189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1142571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
114345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
11444189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
11454189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
1146571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (primaryCode != Keyboard.CODE_ENTER) {
11474189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                mJustAddedAutoSpace = false;
11484189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11494189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            RingCharBuffer.getInstance().push((char)primaryCode, x, y);
11504189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnInputChar();
11514189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (isWordSeparator(primaryCode)) {
11524189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleSeparator(primaryCode);
11534189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
11548fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                handleCharacter(primaryCode, keyCodes, x, y);
11554189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11564189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Cancel the just reverted state
1157c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1159b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1160dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1161dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1163a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11658aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1166409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.commitVoiceInput();
1167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1169952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        abortRecorrection(false);
1170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
117155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
117241a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1175b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11765f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
1177c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
11789a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAddedAutoSpace = false;
1179dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11825a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11838aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
118483e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11855f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
118683e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
118783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1189409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.logAndRevertVoiceInput()) return;
11904f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1191504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1192504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1193979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1194979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1195409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleBackspace();
11964f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1197504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
11989fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1199923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1201923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
12059fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mHasValidSuggestions = false;
1206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1207d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
1208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1214d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1215504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1217979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
1218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1219979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1221504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1222504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1223504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1224dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
12266558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
12276558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
122855b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
12296558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
12306558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
12316558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
12326558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
12336558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
12346558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
12356558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
12386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12396558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1242c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
1243979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
124645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
124745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
124845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int navigationFlags =
124945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
125045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & navigationFlags) == 0) {
125145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
125245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
125345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
125445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
125545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
125645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
125745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
125845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
125945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
126045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
126145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
126245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
126345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
126445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
126545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
126645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
126745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
126845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
126945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
1270952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa    private void abortRecorrection(boolean force) {
1271952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (force || TextEntryState.isRecorrecting()) {
1272952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            TextEntryState.onAbortRecorrection();
1273ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setCandidatesViewShown(isCandidateStripVisible());
1274979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            getCurrentInputConnection().finishComposingText();
1275b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1278a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12798fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
1280409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleCharacter();
12814f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1282952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isRecorrecting()) {
1283952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            abortRecorrection(false);
1284b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12854f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1286e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
12879fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
12889fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (!mHasValidSuggestions) {
12899fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mHasValidSuggestions = true;
1290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1291979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                saveWordInHistory(mBestWord);
1292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
12937e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
12961679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1297f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1298eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1299eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1300eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1301eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1302e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1303e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1304e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1305e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1306e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
130712a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
130812a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1309e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
13108aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
131112a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
131212a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1313979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13159fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1316f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1317f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
13180b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1320e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
13218fbd55229243cb66c03d5ea1f79dfb39f596590dsatok            mWord.add(code, keyCodes, x, y);
1322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
13241c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
13251c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1326b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
13271c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1330d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1332e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1334b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1335979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
1336e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        TextEntryState.typedCharacter((char) code, isWordSeparator(code));
1337923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1338923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleSeparator(int primaryCode) {
1340409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleSeparator();
13414f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
134255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
13436558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1344d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
13456558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
13466558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1347923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
13491b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1350923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1351923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1352952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            abortRecorrection(false);
1353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13549fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1356a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1359c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            if (mAutoCorrectOn && primaryCode != '\'' && !mJustReverted) {
1360979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                pickedDefault = pickDefaultSuggestion();
13619a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // Picked the suggestion by the space key.  We consider this
13629a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // as "added an auto space".
1363571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                if (primaryCode == Keyboard.CODE_SPACE) {
13649a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                    mJustAddedAutoSpace = true;
13659a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                }
1366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1370571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (mJustAddedAutoSpace && primaryCode == Keyboard.CODE_ENTER) {
13719a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            removeTrailingSpace();
13729a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = false;
13739a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)primaryCode);
13754ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
13764ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // Handle the case of ". ." -> " .." with auto-space if necessary
13774ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // before changing the TextEntryState.
1378979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1379571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode == Keyboard.CODE_PERIOD) {
13804ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            reswapPeriodAndSpace();
13814ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13824ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1383923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) primaryCode, true);
1384979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1385571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode != Keyboard.CODE_ENTER) {
1386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            swapPunctuationAndSpace();
13879fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1388923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            doubleSpace();
1389923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1390979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
139155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
139255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
139355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
13944ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                if (ic != null) {
13954ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    CorrectionInfo correctionInfo = new CorrectionInfo(
13964ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                            mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
13974ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    ic.commitCorrection(correctionInfo);
13984ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                }
139955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
140055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
140155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
140255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1403923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1404b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1405923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1406923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1409466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1410923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1412409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleClose();
1413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
14141679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
14151679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
14161679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1420979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void saveWordInHistory(CharSequence result) {
1421979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mWord.size() <= 1) {
1422979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mWord.reset();
1423979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1425979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Skip if result is null. It happens in some edge case.
1426979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextUtils.isEmpty(result)) {
1427979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1429979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1430979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
1431979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final String resultCopy = result.toString();
1432979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        TypedWordAlternatives entry = new TypedWordAlternatives(resultCopy,
1433979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                new WordComposer(mWord));
1434979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.add(entry);
1435923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1436923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14379fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isSuggestionsRequested() {
1438c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1439c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1440923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1441a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
14427599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private boolean isShowingPunctuationList() {
14437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        return mSuggestPuncList == mCandidateView.getSuggestions();
14447599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14457599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14469fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isShowingSuggestionsStrip() {
14477599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
14487599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
14497599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
14507599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14517599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCandidateStripVisible() {
1453b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1454b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1455952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
14569fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14579fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
14589fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
14599fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
14609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14619fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1462923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1464409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1465060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1466060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1467060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1468060efb6d82af1f896d90cb845c8ae07c726f85e1satok        View v = mKeyboardSwitcher.getInputView();
1469060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1470060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1471060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1472060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1473060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
14745a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1475060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1476060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1477060efb6d82af1f896d90cb845c8ae07c726f85e1satok        setCandidatesViewShown(isCandidateStripVisible());
1478060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1479060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1480466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1481466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1482409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1484466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1485466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1487409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.getAndResetIsShowingHint()) {
1488466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1489466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1490466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1491466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
14927e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
14939ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
14949ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
14959ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
14969ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1497466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1498466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1499466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1500409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
15029fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1503409220583333bdf06290dd9fd42f91b5c0d1b11asatok                && !mVoiceConnector.isVoiceInputHighlighted()) {
1504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1506466741d8a78965b8509bf527344f289e50873092Mike LeBeau
15079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1508ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1509923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1510923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1511979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1512979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1513979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
15147e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords.Builder getTypedSuggestions(WordComposer word) {
15159ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka        return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null);
1516979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1517979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1518979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showCorrections(WordAlternatives alternatives) {
15197e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = alternatives.getAlternatives();
15207e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
15217e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), alternatives.getOriginalWord());
1522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1523979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1524979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
1525979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // TODO Maybe need better way of retrieving previous word
1526e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1527979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mWordSeparators);
15287e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
15299ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1531378a1b516d867671d292900c5d42aef3a0dc1556Ken Wakasa        boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
15326f7218627eda110a8454053f8ecb7b80edfdc8cesatok                && mSuggest.hasAutoCorrection();
1533a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If we're in basic correct
1535a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
1536979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                (preferCapitalization()
1537979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                        && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
1538979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1539979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15424a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1543979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1544952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        correctionAvailable &= !TextEntryState.isRecorrecting();
1545979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1546a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1547a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1548f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1549f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1550f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1551f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1552f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1553a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
15549fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
15559fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
15569fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
15579fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (previousSuggestions == mSuggestPuncList)
15589fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
15599fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
15609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
15617e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1562979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
15634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
15647e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
15657e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
15667e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
156714e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
156882411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
156982411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
15707e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1571923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1572923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1576923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1577ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1579923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1580979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean pickDefaultSuggestion() {
1581923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1582d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1583d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15866780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1587923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
1588923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
158955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
15909468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1591979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1592979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1593979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1595979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1596923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1597923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
15997e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
1600409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
16014f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1602952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        final boolean recorrecting = TextEntryState.isRecorrecting();
16039a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
16049a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16059a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
16069a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
16071b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
16081b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
16091b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1611923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1617b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
16189a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16199a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16209a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16236a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
16246a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
1625979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0))
1626979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || isSuggestedPunctuation(suggestion.charAt(0)))) {
1627979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1628979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1629979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
16307e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
163155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1632a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1633a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1634a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
16359a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16369a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16379a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
16386a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
16396a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
16409a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
164155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
16429468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
16430c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1644979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1645979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1646979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToBigramDictionary(suggestion, 1);
16470c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1648979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
16497e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1650923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1651923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1652952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mAutoSpace && !recorrecting) {
1653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendSpace();
16549a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1656979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
16577f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We should show the hint if the user pressed the first entry AND either:
16587f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
16597f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        //   AND mHasDictionary is false)
16607f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
16617f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
16627f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
16637f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
16647f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
16657f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        final boolean showingAddToDictionaryHint = index == 0 &&
16667f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard                // Test for no dictionary:
16677f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard                ((!mHasDictionary && null != mSuggest) ||
16687f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard                // Test for dictionary && word is inside:
16697f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard                (mHasDictionary && null != mSuggest
1670b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion)
16717f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard                && !mSuggest.isValidWord(suggestion.toString().toLowerCase())));
1672b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1673952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!recorrecting) {
1674b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1675b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1676b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1677571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true);
1678ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1679b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        } else if (!showingAddToDictionaryHint) {
1680364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1681979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1682b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1683d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1684979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1685b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
168666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
168766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16889a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16899a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16909a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1691923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1692a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1693979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1694979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1695979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1696979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1697979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1698979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
169955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1700b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1701b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
17021679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1703923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1705409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.rememberReplacedWord(suggestion, mWordSeparators);
1706979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1708979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        saveWordInHistory(suggestion);
17099fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mHasValidSuggestions = false;
1710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1713b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    /**
1714b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * Tries to apply any typed alternatives for the word if we have any cached alternatives,
1715b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * otherwise tries to find new corrections and completions for the word.
1716b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @param touching The word that the cursor is touching, with position information
1717b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @return true if an alternative was found, false otherwise.
1718b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     */
1719e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) {
1720b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // If we didn't find a match, search for result in typed word history
1721b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordComposer foundWord = null;
1722b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordAlternatives alternatives = null;
1723b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        for (WordAlternatives entry : mWordHistory) {
1724e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
1725b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                if (entry instanceof TypedWordAlternatives) {
1726b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    foundWord = ((TypedWordAlternatives) entry).word;
1727b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
1728b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                alternatives = entry;
1729b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                break;
1730b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1731b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
17321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // If we didn't find a match, at least suggest corrections.
1733b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord == null
1734e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                && (mSuggest.isValidWord(touching.mWord)
1735e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
1736b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            foundWord = new WordComposer();
1737e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            for (int i = 0; i < touching.mWord.length(); i++) {
1738e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                foundWord.add(touching.mWord.charAt(i), new int[] {
1739e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    touching.mWord.charAt(i)
17408fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                }, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1741b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1742e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
1743b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1744b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // Found a match, show suggestions
1745b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord != null || alternatives != null) {
1746b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (alternatives == null) {
1747e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                alternatives = new TypedWordAlternatives(touching.mWord, foundWord);
1748b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1749b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            showCorrections(alternatives);
1750b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (foundWord != null) {
1751b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord = new WordComposer(foundWord);
1752b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            } else {
1753b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord.reset();
1754b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1755b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return true;
1756b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1757b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return false;
1758b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
1759b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1760979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void setOldSuggestions() {
1761409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setShowingVoiceSuggestions(false);
1762b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
1763b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return;
1764b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1765979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        InputConnection ic = getCurrentInputConnection();
1766979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (ic == null) return;
17679fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1768b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Extract the selected or touching text
1769e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
1770b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    mLastSelectionStart, mLastSelectionEnd, mWordSeparators);
1771979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1772e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (touching != null && touching.mWord.length() > 1) {
1773b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.beginBatchEdit();
1774979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1775409220583333bdf06290dd9fd42f91b5c0d1b11asatok                if (!mVoiceConnector.applyVoiceAlternatives(touching)
1776409220583333bdf06290dd9fd42f91b5c0d1b11asatok                        && !applyTypedAlternatives(touching)) {
1777952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                    abortRecorrection(true);
1778b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                } else {
1779952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                    TextEntryState.selectedForRecorrection();
1780e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    EditingUtils.underlineWord(ic, touching);
1781979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
1782b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1783b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.endBatchEdit();
1784979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } else {
1785952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa                abortRecorrection(true);
1786ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                setPunctuationSuggestions();  // Show the punctuation suggestions list
1787979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1788979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1789952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa            abortRecorrection(true);
1790979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1791979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1792979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1793ca26f20fa4903de46e374babbfba8c8a1a5cac93satok    private void setPunctuationSuggestions() {
17947e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(mSuggestPuncList);
17959fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
17966a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
17976a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1798979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToDictionaries(CharSequence suggestion, int frequencyDelta) {
1799979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1800979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1801979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1802979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1803979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1804979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1805979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1806979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1807979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1808979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param addToBigramDictionary true if it should be added to bigram dictionary if possible
1809979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1810979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1811979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            boolean addToBigramDictionary) {
1812979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
18130c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
18140c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
18150c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1816979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1817979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1818979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1819979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1820e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
1821e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || (!mSuggest.isValidWord(suggestion.toString())
1822e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
1823e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1824e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1825979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1826e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1827e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1828e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    mSentenceSeparators);
1829e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1830e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1831979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
183232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
183332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
183432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
1835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCursorTouchingWord() {
1836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1838923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
184155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toLeft.charAt(0))
184255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toLeft.charAt(0))) {
1843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1845a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
184655b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toRight.charAt(0))
184755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toRight.charAt(0))) {
1848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1852a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1853dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1854dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1855dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1856dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1857dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
18609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions && length > 0) {
1861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1862c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = true;
1863504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1865923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1866504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1867504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
1868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
187130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
187230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
187330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
187430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
187530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1876504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1877504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
187830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
187930be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                TextEntryState.typedCharacter(punctuation.charAt(0), true);
188030be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
188130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1882504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
188330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mHasValidSuggestions = true;
1884504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1885504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1886504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1887d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1888923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1889923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1890c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1891923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1892923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1893923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1894923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1895923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1896923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1897a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
1899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
1900923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
1901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1903979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSentenceSeparator(int code) {
1904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mSentenceSeparators.contains(String.valueOf((char)code));
1905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1907923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void sendSpace() {
1908571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
1909b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
19130b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1916c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
1917c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1918c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
19194ab730dbd34fad323063f2ffd31ce33de746668dsatok        toggleLanguage(true, true);
19204ab730dbd34fad323063f2ffd31ce33de746668dsatok    }
19214ab730dbd34fad323063f2ffd31ce33de746668dsatok
19224ab730dbd34fad323063f2ffd31ce33de746668dsatok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
19233f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani    private void toggleLanguage(boolean reset, boolean next) {
1924de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
19254ab730dbd34fad323063f2ffd31ce33de746668dsatok            mSubtypeSwitcher.toggleLanguage(reset, next);
19264ab730dbd34fad323063f2ffd31ce33de746668dsatok        }
19274ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1928cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
19294b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka                mVoiceConnector.isVoiceButtonEnabled(), mVoiceConnector.isVoiceButtonOnPrimary());
19300ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
19314b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
193236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
193336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
19345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
19358aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
1936363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        if (mConfigSwipeDownDismissKeyboardEnabled)
1937363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19405a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onPress(int primaryCode) {
1942cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1943cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1944cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1945cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
19461679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19471679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1948571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1949b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.onPressShift();
1950e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19516c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
195240a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
19536c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1954681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1955dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils.onPress(primaryCode, switcher);
1956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19585a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onRelease(int primaryCode) {
19601679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19613f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
19621679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        switcher.keyReleased();
19631679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1964571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1965889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka            switcher.onReleaseShift();
1966e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19676c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
196840a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1969dcade18113286a132a2f5fb508fdba836470c3fbAlan Viverette        mAccessibilityUtils.onRelease(primaryCode, switcher);
1970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1971a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1972a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1973123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
1974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1975923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1977123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
1978123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
1979123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
1980123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1981123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
1982123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
1983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1985923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1986923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
1987923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
1988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
1992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
1993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1994923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
1997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
1998923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
1999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2000979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mKeyboardSwitcher.getInputView() != null) {
2001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
2002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2003923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2004923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSoundOn && !mSilentMode) {
2005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
2006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
2007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
2008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
2009571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
2010923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
2011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2012571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
2013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
2014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2015571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
2016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
2017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
2020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2023409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
2024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mVibrateOn) {
2025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
2026923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
20271679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
20281679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
20291679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
2030979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
203166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
2032923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2033923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2034923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
203571c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public void promoteToUserDictionary(String word, int frequency) {
203634386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
203734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
203834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
203934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
204071c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
20416516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
20426516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
20436516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
204471c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public boolean getPopupOn() {
2045979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mPopupOn;
2046979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2047979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2048e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
2049e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
2050e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
2051e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                && !mInputTypeNoAutoCorrect && mHasDictionary;
205232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled)
2053e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
205432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani                : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
2055979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mCorrectionMode = (mBigramSuggestionEnabled && mAutoCorrectOn && mAutoCorrectEnabled)
2056979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2057e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2058e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2059e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2060e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2061e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
20620ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
206332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
20645ef096f5f601c759e8a4a888aaca91ac5ccd9974Tadashi G. Takaoka        mSuggest.setQuickFixesEnabled(mQuickFixes
20654ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
206632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
206732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
20687599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private void updateSuggestionVisibility(SharedPreferences prefs) {
2069458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
20707599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
20719502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2072458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
20737599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2074458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
20757599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
20767599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
20777599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
20787599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
20797599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
20807599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2081466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
20829502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
2083466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2084466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2085bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
20869502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
2087bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2088bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2089507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
2090923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2092466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2093923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2094923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2095923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2097507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private void loadSettings(EditorInfo attribute) {
2098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Get the settings preferences
209927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
21004174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasa        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
21014174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasa        mVibrateOn = vibrator != null && vibrator.hasVibrator()
21029502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
2103f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard        mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON,
2104f0d99b8677afdde39c16d414d44bfafcaea94b50Jean Chalard                mResources.getBoolean(R.bool.config_default_sound_enabled));
2105728115493e14f84d5f02a4812c8086a378813364Jean Chalard
2106728115493e14f84d5f02a4812c8086a378813364Jean Chalard        mPopupOn = isPopupEnabled(prefs);
21079502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
210889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
2109a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
211027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
211127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
21121b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
2113466741d8a78965b8509bf527344f289e50873092Mike LeBeau
211427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector.loadSettings(attribute, prefs);
2115409220583333bdf06290dd9fd42f91b5c0d1b11asatok
2116e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
21170ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
211827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        updateSuggestionVisibility(prefs);
211927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.getInstance().loadSettings();
212036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
212136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2122b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    /**
21231b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka     *  Load Auto correction threshold from SharedPreferences, and modify mSuggest's threshold.
2124b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda     */
21251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private void loadAndSetAutoCorrectionThreshold(SharedPreferences sp) {
2126b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // When mSuggest is not initialized, cannnot modify mSuggest's threshold.
2127b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (mSuggest == null) return;
21281b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When auto correction setting is turned off, the threshold is ignored.
2129b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (!isAutoCorrectEnabled(sp)) return;
2130b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
21311b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
21321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
21339ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
21341b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String[] autoCorrectionThresholdValues = mResources.getStringArray(
21359ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.array.auto_correction_threshold_values);
21361b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When autoCrrectionThreshold is greater than 1.0, auto correction is virtually turned off.
21371b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        double autoCorrectionThreshold = Double.MAX_VALUE;
2138b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        try {
21391b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
21401b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
21411b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                autoCorrectionThreshold = Double.parseDouble(
21421b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                        autoCorrectionThresholdValues[arrayIndex]);
2143b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda            }
2144b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        } catch (NumberFormatException e) {
21451b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            // Whenever the threshold settings are correct, never come here.
21461b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            autoCorrectionThreshold = Double.MAX_VALUE;
21471b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            Log.w(TAG, "Cannot load auto correction threshold setting."
21481b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
21491b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + ", autoCorrectionThresholdValues: "
21501b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + Arrays.toString(autoCorrectionThresholdValues));
2151b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        }
2152b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // TODO: This should be refactored :
21531b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        //           setAutoCorrectionThreshold should be called outside of this method.
21541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
2155b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2156b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2157728115493e14f84d5f02a4812c8086a378813364Jean Chalard    private boolean isPopupEnabled(SharedPreferences sp) {
2158728115493e14f84d5f02a4812c8086a378813364Jean Chalard        final boolean showPopupOption = getResources().getBoolean(
2159728115493e14f84d5f02a4812c8086a378813364Jean Chalard                R.bool.config_enable_show_popup_on_keypress_option);
2160728115493e14f84d5f02a4812c8086a378813364Jean Chalard        if (!showPopupOption) return mResources.getBoolean(R.bool.config_default_popup_preview);
2161728115493e14f84d5f02a4812c8086a378813364Jean Chalard        return sp.getBoolean(Settings.PREF_POPUP_ON,
2162728115493e14f84d5f02a4812c8086a378813364Jean Chalard                mResources.getBoolean(R.bool.config_default_popup_preview));
2163728115493e14f84d5f02a4812c8086a378813364Jean Chalard    }
2164728115493e14f84d5f02a4812c8086a378813364Jean Chalard
216589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    private boolean isQuickFixesEnabled(SharedPreferences sp) {
216689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showQuickFixesOption = mResources.getBoolean(
216789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_quick_fixes_option);
216889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showQuickFixesOption) {
216989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
217089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
217189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
217289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_quick_fixes));
217389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    }
217489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard
2175b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
21761b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
21771b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
21789ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
21791b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String autoCorrectionOff = mResources.getString(
21809ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.string.auto_correction_threshold_mode_index_off);
21811b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
2182b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2183b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2184b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
218589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showBigramSuggestionsOption = mResources.getBoolean(
218689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_bigram_suggestions_option);
218789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showBigramSuggestionsOption) {
218889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
218989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
219089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
219189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_bigram_suggestions));
2192b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2193b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
21946a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
21957e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (mSuggestPuncs != null || mSuggestPuncList != null)
21967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            return;
21977e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = new SuggestedWords.Builder();
21987e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        String puncs = mResources.getString(R.string.suggested_punctuations);
21997e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (puncs != null) {
22007e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            for (int i = 0; i < puncs.length(); i++) {
22017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                builder.addWord(puncs.subSequence(i, i + 1));
22026a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
22036a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
22047e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncList = builder.build();
22057e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncs = puncs;
22066a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
22076a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2208979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSuggestedPunctuation(int code) {
2209979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestPuncs.contains(String.valueOf((char)code));
2210979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2211979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
22122fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
221385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
221485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
221585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
221685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
221785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
221885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
221985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22202fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
22212fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
22222fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
22232fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
222485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
22252fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    Intent intent = new Intent(
22262fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
22272fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
22282fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
22292fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
22302fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    intent.putExtra(android.provider.Settings.EXTRA_INPUT_METHOD_ID,
22312fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            mInputMethodId);
22322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
22332fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2234aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2235aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2236aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
22372fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
22382fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
223985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
224085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
22412fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
224485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
224585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
224685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
224785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
224885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
224985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22505a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2253923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
225485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2255ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
22562fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
225785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2258ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
22592fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
226285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
226385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
22642fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
22652fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
226685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
226785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
226818e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        final IBinder windowToken = mKeyboardSwitcher.getInputView().getWindowToken();
226918e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        if (windowToken == null) return;
22702fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
22712fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
22722fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
22732fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
227485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
227585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2277a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
228018e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        lp.token = windowToken;
2281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22877e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
22887e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2290a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
22959fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
22979fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mHasValidSuggestions=" + mHasValidSuggestions);
2298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
2299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoSpace=" + mAutoSpace);
23001b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
2302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
2303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
2304979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        p.println("  mPopupOn=" + mPopupOn);
2305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
23066e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2308a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2313a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2317923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2318923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
232434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
23250ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    @Override
23260ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
23274ab730dbd34fad323063f2ffd31ce33de746668dsatok        SubtypeSwitcher.getInstance().updateSubtype(subtype);
23280ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
2329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2330