LatinIME.java revision 240297d0ee186b14e795016e9b1bd168c8d8acf8
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
192cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatokimport com.android.inputmethod.compat.CompatUtils;
20b2707856aba4fc9b063f26305f1fb603b19c1701satokimport com.android.inputmethod.compat.EditorInfoCompatUtils;
21b2707856aba4fc9b063f26305f1fb603b19c1701satokimport com.android.inputmethod.compat.InputConnectionCompatUtils;
22610f1dc8553cf2ed97e763a06a19380c4a6cd636satokimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
2310dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatokimport com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
24e9957752bcaad048746c7a57bbd2c0a59e1918a0satokimport com.android.inputmethod.compat.InputTypeCompatUtils;
2588fc9d44186120f9edc5cf7ec0e2af85260fed04satokimport com.android.inputmethod.deprecated.LanguageSwitcherProxy;
26e9957752bcaad048746c7a57bbd2c0a59e1918a0satokimport com.android.inputmethod.deprecated.VoiceProxy;
27f733074aaecdfd6e89cfee2daff8a9c1233b60f1satokimport com.android.inputmethod.deprecated.recorrection.Recorrection;
285a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
30571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
315a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
32de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
335a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
34388ce92ab8a635c5ad44620dad59baf05dfea510Amith Yamasani
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
4336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
46123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
4918e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasaimport android.os.IBinder;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
52bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
54e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
56979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
59923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
6066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
62e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.LayoutInflater;
63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
648e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
658e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
70466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
71923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
7240ac45ebdcd71940394dda00371d4847f7db0f26Ken Wakasaimport android.widget.LinearLayout;
73923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
74466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
75466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
76466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
77466741d8a78965b8509bf527344f289e50873092Mike LeBeau
78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
8110dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatokpublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener {
828efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    private static final String TAG = LatinIME.class.getSimpleName();
83979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
84409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
85910b73127fa207dd26ec8124000262523b0aac0csatok    private static boolean DEBUG = LatinImeLogger.sDBG;
86a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
878efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
888efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     *
928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
9410dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok    @SuppressWarnings("dep-ann")
958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
1008efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
1018efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
1024199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1034199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1074199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1084199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1098efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
1109e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
111fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
115d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
116a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
117cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
118cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
119cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
120cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
121cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
122cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1237599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1247599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1257599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1287599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
13717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private Settings.Values mSettingsValues;
13817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
139e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
1407a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka    private int mCandidateStripHeight;
141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
144a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
146a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
147610f1dc8553cf2ed97e763a06a19380c4a6cd636satok    private InputMethodManagerCompatWrapper mImm;
1482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
15171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1520ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
153b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    private VoiceProxy mVoiceProxy;
1547a8dac55278cedd838be325f56b4c52d973c61f5satok    private Recorrection mRecorrection;
155a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
157979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1582bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1594ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
16036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1610730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // TODO: Create an inner class to group options and pseudo-options to improve readability.
162c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
1630730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mShouldInsertMagicSpace;
164c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
165c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
166c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
167c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
16871c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
171f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard    private boolean mHasUncommittedTypedChars;
172e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1730730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // Magic space: a space that should disappear on space/apostrophe insertion, move after the
1740730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // punctuation on punctuation insertion, and become a real space on alpha char insertion.
1750730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mJustAddedMagicSpace; // This indicates whether the last char is a magic space.
176409220583333bdf06290dd9fd42f91b5c0d1b11asatok
17779efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
17879efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
17979efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
180979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
18179efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
18279efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
183979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
188a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
1902296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
19171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
19217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private boolean mSilentModeOn; // System-wide current configuration
193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
194b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    // TODO: Move this flag to VoiceProxy
19581c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
196466741d8a78965b8509bf527344f289e50873092Mike LeBeau
197cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
198cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private BroadcastReceiver mDictionaryPackInstallReceiver =
199cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard            new DictionaryPackInstallBroadcastReceiver(this);
200cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
201dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
202dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
203dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
20436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
205571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
206d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
207409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
208d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
209d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
210d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
211d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
212de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
213de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
214fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        private static final int MSG_SPACE_TYPED = 6;
215cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
216d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
219de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
220de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
222d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
223d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
224d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
225d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
2269fbfd5877305ed19a20663630b498b6b3fdae942satok                mRecorrection.setRecorrectionSuggestions(mVoiceProxy, mCandidateView, mSuggest,
2279fbfd5877305ed19a20663630b498b6b3fdae942satok                        mKeyboardSwitcher, mWord, mHasUncommittedTypedChars, mLastSelectionStart,
22817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                        mLastSelectionEnd, mSettingsValues.mWordSeparators);
229d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
230d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
231de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
232d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
233cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            case MSG_SET_BIGRAM_PREDICTIONS:
234cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                updateBigramPredictions();
23589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                break;
236d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
237b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.handleVoiceResults(preferCapitalization()
238de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
239de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
240de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
24117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
24266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
24317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            (1.0f + mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
24466432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
24517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
246de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
24717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                        mSettingsValues.mDurationOfFadeoutLanguageOnSpacebar);
248de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
249de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
25017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
25166432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
25217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
25317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            (LatinKeyboard)msg.obj);
25417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
255d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
256923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
258d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
259d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
260d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
2619b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS),
26217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mDelayUpdateSuggestions);
263d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
264d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
267d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
268d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
269d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
270d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
271d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
272d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
273d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
274d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
275d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
27617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mDelayUpdateOldSuggestions);
277d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
278d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
279d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
280d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
283d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
28517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
28617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mDelayUpdateShiftState);
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
293cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void postUpdateBigramPredictions() {
294cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
2959b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS),
29617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mDelayUpdateSuggestions);
29789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
29889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
299cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void cancelUpdateBigramPredictions() {
300cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
30189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
30289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
304d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
306de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
307d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
308de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
309de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
310de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
311de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
312050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
313c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The language is always displayed when the delay is negative.
314c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                final boolean needsToDisplayLanguage = localeChanged
31517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                        || mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar < 0;
316de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
31717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar != 0) {
318c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
31917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            : mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
32017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
321c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The fadeout animation will start when the delay is positive.
32217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (localeChanged && mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar > 0) {
323de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
32417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar);
325de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
326de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
327de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
328fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
329fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void startDoubleSpacesTimer() {
330fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
331fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
33217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mDoubleSpacesTurnIntoPeriodTimeout);
333fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
334fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
335fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void cancelDoubleSpacesTimer() {
336fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
337fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
338fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
339fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public boolean isAcceptingDoubleSpaces() {
340fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            return hasMessages(MSG_SPACE_TYPED);
341fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
342d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3447e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3457e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
34627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
34727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
34827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
3496d9021527a38ba1e94225020389621a0d7227aa1satok        LanguageSwitcherProxy.init(this, prefs);
35027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
35127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
3527a8dac55278cedd838be325f56b4c52d973c61f5satok        Recorrection.init(this, prefs);
353363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
354923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
355363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
356610f1dc8553cf2ed97e763a06a19380c4a6cd636satok        mImm = InputMethodManagerCompatWrapper.getInstance(this);
3578efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
3580ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3590ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
3607a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection = Recorrection.getInstance();
361363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
36217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
36317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
364363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
365363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
366fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
3679502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
368979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
3699502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
370979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
3710ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
372979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
373979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
3749502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
375979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
376979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
377979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
378363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
379b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
380cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Register to receive ringer mode change and network state change.
381cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Also receive installation and removal of a dictionary pack.
382123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
383123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
384123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
386b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
387cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
388cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final IntentFilter packageFilter = new IntentFilter();
389cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
390cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
391cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addDataScheme(SCHEME_PACKAGE);
392cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
393646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard
394646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        final IntentFilter newDictFilter = new IntentFilter();
395646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        newDictFilter.addAction(
396646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard                DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
397646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
39936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
40017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    // Has to be package-visible for unit tests
40117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    /* package */ void loadSettings() {
40217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
40317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
40417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
40517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    }
40617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
4070ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
408cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
409cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final Locale keyboardLocale = new Locale(localeStr);
41036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
411309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Resources res = mResources;
412309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
41336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
41436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
41536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
416979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4178efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
418cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
41917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCorrectEnabled) {
42017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
42117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        }
42227023341658b4cf5430d18ddb94fd9502ecfe3cbTadashi G. Takaoka        updateAutoTextEnabled();
423e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
424cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserDictionary = new UserDictionary(this, localeStr);
425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
426e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
427e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4282bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
429e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
430cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO);
43134386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
432e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
433cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER);
434e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
435e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
436e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
43736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
438309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        Utils.setSystemLocale(res, savedLocale);
439923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
44036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
441cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /* package private */ void resetSuggestMainDict() {
442cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
443cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final Locale keyboardLocale = new Locale(localeStr);
444cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
445cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
446cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
447cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
448466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
449466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
450e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
451e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
452e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
453979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
454923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
455cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
456b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.destroy();
457979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
458979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
462923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
464dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
465b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
466b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
467466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
468466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
469466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
470b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
4712fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
4722fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
473b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
4748b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
47581c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
477b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.onConfigurationChanged(conf);
47881c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
47988fc9d44186120f9edc5cf7ec0e2af85260fed04satok
48088fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
48188fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.onConfigurationChanged(conf);
482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
483b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
4868d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
490923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
491e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
492e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
493e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
4947a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height);
495e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
498e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
501a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
502923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
50345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
50445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5058e09172df1bb176cc899940862c56bed9b9aec4esatok
50689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (DEBUG) {
507910b73127fa207dd26ec8124000262523b0aac0csatok            Log.d(TAG, "onStartInputView: " + inputView);
508910b73127fa207dd26ec8124000262523b0aac0csatok        }
509923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
510979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
511923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5148d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5154ab730dbd34fad323063f2ffd31ce33de746668dsatok
516662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        TextEntryState.reset();
5176c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
518c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
519c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
520c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
521b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        final VoiceProxy voiceIme = mVoiceProxy;
522e9957752bcaad048746c7a57bbd2c0a59e1918a0satok        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(attribute.inputType)
523e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                || InputTypeCompatUtils.isVisiblePasswordInputType(attribute.inputType));
524c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
525cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
526c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
527c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
528c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
529c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
530f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
531c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
5320730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
533c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
53417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
53517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateCorrectionMode();
53617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateAutoTextEnabled();
53717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateSuggestionVisibility(mPrefs, mResources);
53817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
53917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
54017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
54117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard         }
54217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.loadSettings(attribute, mPrefs);
54317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // This will work only when the subtype is not supported.
54417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        LanguageSwitcherProxy.loadSettings();
54517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
546c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
547cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            switcher.loadKeyboard(attribute,
5484503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    mSubtypeSwitcher.isShortcutImeEnabled() && voiceIme.isVoiceButtonEnabled(),
5494503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    voiceIme.isVoiceButtonOnPrimary());
550c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
551c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
552c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
5537a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(), false /* needsInputViewShown */ );
554c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
555c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
556c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
557c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
558c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
559240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn,
560240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard                mSettingsValues.mKeyPreviewPopupDismissDelay);
561c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
562c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
5637a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.checkRecorrectionOnStart();
564c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
565c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
5664503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka        voiceIme.onStartInputView(inputView.getWindowToken());
567c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
568c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
569c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
570c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
571cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
572cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
573cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
5744b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
575c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
5760730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mShouldInsertMagicSpace = false;
577e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
5789fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
5791b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
5801b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
581dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
582cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
583cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
584cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // Make sure that passwords are not displayed in candidate view
585e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isPasswordInputType(inputType)
586e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
587cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
588cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
589e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)
590cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
5910730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = false;
592cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
5930730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = true;
594cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
595e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)) {
596cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
597cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
598cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
599cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
600cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
601cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
602cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
603cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
604cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
605e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
60636ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
607cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
608cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
609cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
610cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
611cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
612cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
613cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
614cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
615cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
616cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
617cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
618cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
619cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
620cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
621cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
622cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
623923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
624923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
626923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
627923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
628923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
629a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
630979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6311b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
632979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
633b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
634409220583333bdf06290dd9fd42f91b5c0d1b11asatok
6355a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
636d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6374ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
638979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
639466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
640466741d8a78965b8509bf527344f289e50873092Mike LeBeau
641466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
6426495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
6436495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
6445a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
645d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
646d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
647d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
648d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
6496495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
6506495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
6516495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
652466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
653466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
654b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.showPunctuationHintIfNecessary();
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
659923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
660923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
661923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
662923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
663466741d8a78965b8509bf527344f289e50873092Mike LeBeau
664466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
665466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
666466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
667025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
668025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
669466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
670466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
671466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
672466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
673466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
674466741d8a78965b8509bf527344f289e50873092Mike LeBeau
675b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
6764f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
679025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
680025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
681025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
682f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (((mComposing.length() > 0 && mHasUncommittedTypedChars)
683b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                || mVoiceProxy.isVoiceInputHighlighted())
684025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                && (selectionChanged || candidatesCleared)) {
685025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            if (candidatesCleared) {
686025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // If the composing span has been cleared, save the typed word in the history for
687025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // recorrection before we reset the candidate strip.  Then, we'll be able to show
688025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // suggestions for recorrection right away.
689f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok                mRecorrection.saveRecorrectionSuggestion(mWord, mComposing);
690025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            }
691923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
692f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
69389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (isCursorTouchingWord()) {
694cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.cancelUpdateBigramPredictions();
69589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.postUpdateSuggestions();
69689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            } else {
69789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                setPunctuationSuggestions();
69889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
701923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
702923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
703923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
704b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.setVoiceInputHighlighted(false);
705f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        } else if (!mHasUncommittedTypedChars && !mJustAccepted) {
706662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka            if (TextEntryState.isAcceptedDefault() || TextEntryState.isSpaceAfterPicked()) {
707662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                if (TextEntryState.isAcceptedDefault())
708662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                    TextEntryState.reset();
7090730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mJustAddedMagicSpace = false; // The user moved the cursor.
7109a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
713d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
714466741d8a78965b8509bf527344f289e50873092Mike LeBeau
715979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
716979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
717979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
718466741d8a78965b8509bf527344f289e50873092Mike LeBeau
7197a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.updateRecorrectionSelection(mKeyboardSwitcher,
7207a8dac55278cedd838be325f56b4c52d973c61f5satok                mCandidateView, candidatesStart, candidatesEnd, newSelStart,
7217a8dac55278cedd838be325f56b4c52d973c61f5satok                newSelEnd, oldSelStart, mLastSelectionStart,
7227a8dac55278cedd838be325f56b4c52d973c61f5satok                mLastSelectionEnd, mHasUncommittedTypedChars);
7237a8dac55278cedd838be325f56b4c52d973c61f5satok    }
7247a8dac55278cedd838be325f56b4c52d973c61f5satok
7257a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setLastSelection(int start, int end) {
7267a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionStart = start;
7277a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionEnd = end;
728923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
729923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
730c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
731c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
732c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
733c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
734c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
735c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
736c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
737c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
738c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
739c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
7407a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
741c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
742c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
743c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
744c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
745c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
746c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
747c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
748c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
749c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
750c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
751c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
752c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
753c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
754c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
755c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
7567a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
757c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
758c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
759c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
760c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
763979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
7641b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
765979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
766923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
7676e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
7686e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
7696e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
7706e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
771b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
7729fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.clearWordsInHistory();
773923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
774923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
775923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
776923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
7771b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
778979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
779a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
780bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
781bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
782bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
783bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
784923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
785923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
7861b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
7871b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
7881b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
789b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
790923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
791923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
792a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
7937e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
7941b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
7957e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
7967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
797979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
7987e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
799923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
800543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
804543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
8057a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        // TODO: Modify this if we support candidates with hard keyboard
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
8077a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final boolean shouldShowCandidates = shown
8087a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
8097a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (isExtractViewShown()) {
8107a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // No need to have extra space to show the key preview.
8117a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setMinimumHeight(0);
8127a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                super.setCandidatesViewShown(shown);
8137a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            } else {
8147a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // We must control the visibility of the suggestion strip in order to avoid clipped
8157a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // key previews, even when we don't show the suggestion strip.
8167a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
8177a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.INVISIBLE);
8187a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                super.setCandidatesViewShown(true);
8197a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            }
820923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
822a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
823923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
824543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
825543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
826543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
827543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
828543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
829923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
8317a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        final KeyboardView inputView = mKeyboardSwitcher.getInputView();
83246ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (inputView == null)
83346ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
83446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        final int containerHeight = mCandidateViewContainer.getHeight();
83546ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        int touchY = containerHeight;
8369e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
83746ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (mKeyboardSwitcher.isInputViewShown()) {
8387a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (mCandidateViewContainer.getVisibility() == View.VISIBLE) {
8397a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                touchY -= mCandidateStripHeight;
8409e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8417a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchWidth = inputView.getWidth();
8427a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchHeight = inputView.getHeight() + containerHeight
8437a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
8447a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
8459e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
8467a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
8477a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        + " height=" + touchHeight);
8489e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8497a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
8509e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
85146ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.contentTopInsets = touchY;
85246ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.visibleTopInsets = touchY;
853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
854a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
856979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
857458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
858458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
859979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
860979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
861458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
862979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
863979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
864979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
865979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
866979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
867979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
868979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
869979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
872e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
873e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
874e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
8756e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
8766e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
877e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
878e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
879923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
881923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
882923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
883923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
884923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
886e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
887e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
888e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
889e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
890e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
891e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
892e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
893e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
894e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
895e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
896e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
897e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
898e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
899e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
900e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
901e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
902e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
907409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
908f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
909f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
916bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
917923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
918923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
919923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
922b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9241c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
92517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCap && ic != null && ei != null
92617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && ei.inputType != InputType.TYPE_NULL) {
927b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9281c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
929b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9301c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9311c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
932863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void swapSwapperAndSpace() {
933923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
934923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
936863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
938863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                && lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
943b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9444ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
9454ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
9464ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
947863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void maybeDoubleSpace() {
948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
954571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
955fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE
956fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && mHandler.isAcceptingDoubleSpaces()) {
957fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.cancelDoubleSpacesTimer();
958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
962b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
963fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        } else {
964fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.startDoubleSpacesTimer();
965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
967a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
96841a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
96941a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
97041a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
97141a519729505a877844f2c57a33509c302dddbceKen Wakasa
97241a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
97341a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
97441a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
9754ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
976571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
977571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
97841a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
97941a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
98041a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
98141a519729505a877844f2c57a33509c302dddbceKen Wakasa
9829a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
9839a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
9849a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
9859a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
9869a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
9879a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
988571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
9899a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
9909a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
9919a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
9929a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
994923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
9956558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
9966558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
997d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
998923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1000923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1003923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1004923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1008a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1009e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
10109a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
101117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (!mSettingsValues.mEnableShowSubtypeSettings) {
10122fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                showSubtypeSelectorAndSettings();
10132fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
10149a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
10159a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10169a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10179a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10189a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10199a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10209a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1021e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10229a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10239502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
102479efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10259a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10269a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10279a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10289a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10299a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10309a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10319a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
10329a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
10339a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10349a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10355f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
10365a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
10378aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1038923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1039571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1043b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1044b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1045923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1046571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
10474189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
10484189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
10494189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
10504189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1051571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
10524189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1053101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1054b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
10554189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1056e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
10574189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1058101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1059b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
10604189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1061571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
10624189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
10634189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
10644189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
10654189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1066e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1067e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
10684189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1069e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1070e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
10714189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1072d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_NEXT_LANGUAGE:
107388fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(true);
10744189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1075d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_PREV_LANGUAGE:
107688fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(false);
10774189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1078571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1079b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
10804189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1081d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case Keyboard.CODE_SHORTCUT:
108220cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
10834189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1084571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
108545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
10864189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
10874189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
108817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isWordSeparator(primaryCode)) {
1089b5d17e52fcda39d540822e615bfb7ed5074e0034satok                handleSeparator(primaryCode, x, y);
10904189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
10918fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                handleCharacter(primaryCode, keyCodes, x, y);
10924189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
1093923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1094b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1095dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1096dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1098a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
10995a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11008aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1101b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.commitVoiceInput();
1102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
11049fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.abortRecorrection(false);
1105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
110655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
110741a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1110b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11115f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
11120730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
1113dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11165a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11178aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
111883e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11195f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
112083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
112183e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1123b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.logAndRevertVoiceInput()) return;
11244f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1125504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1126504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1127979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1128979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1129b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleBackspace();
11304f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1131504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
1132f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1136923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
1139f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                    mHasUncommittedTypedChars = false;
1140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
114189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                if (1 == length) {
114289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // 1 == length means we are about to erase the last character of the word,
114389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // so we can show bigrams.
1144cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                    mHandler.postUpdateBigramPredictions();
114589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                } else {
114689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // length > 1, so we still have letters to deduce a suggestion from.
114789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    mHandler.postUpdateSuggestions();
114889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                }
1149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1155d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1156504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1158662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isUndoCommit()) {
1159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1160979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1162504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1163504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1164504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1165dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
11676558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
11686558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
116955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
11706558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
11716558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
11726558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
11736558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
11746558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
11756558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
11766558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
11786558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
11796558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
11806558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1183979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
118645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
118745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
1188b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
1189b2707856aba4fc9b063f26305f1fb603b19c1701satok                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
119045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
119145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
119245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
119345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
119445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
119545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
119645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
119745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
119845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
119945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
1200b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
120145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
1202b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionNext(ic);
120345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
1204b2707856aba4fc9b063f26305f1fb603b19c1701satok        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
120545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
1206b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionPrevious(ic);
120745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
120845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
120945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
12108fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
1211b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleCharacter();
12124f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
121317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceStripper(primaryCode)) {
12140730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            removeTrailingSpace();
12150730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        }
12160730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard
1217863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mLastSelectionStart == mLastSelectionEnd) {
12189fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1219b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12204f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1221e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
12229fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
1223f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            if (!mHasUncommittedTypedChars) {
1224f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
1225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1226f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok                mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord);
1227923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
12287e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
12311679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1232f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1233eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1234eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1235eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1236eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1237e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1238e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1239e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1240e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1241e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
124212a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
124312a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1244e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
12458aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
124612a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
124712a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1248979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1250f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1251f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1252f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
12530b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1255e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
12568fbd55229243cb66c03d5ea1f79dfb39f596590dsatok            mWord.add(code, keyCodes, x, y);
1257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
12591c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
12601c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1261b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
12621c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1263923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1267e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
126917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1270863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            swapSwapperAndSpace();
1271863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        } else {
1272863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            mJustAddedMagicSpace = false;
1273863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1274863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1275b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1276979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
127717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y);
1278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1280b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private void handleSeparator(int primaryCode, int x, int y) {
1281b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleSeparator();
12824f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
128355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
12846558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1285cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
12876558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
12886558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
12911b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
12949fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1296f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1298a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
130117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            final boolean shouldAutoCorrect =
130217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    (mSettingsValues.mAutoCorrectEnabled || mSettingsValues.mQuickFixes)
130317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && !mInputTypeNoAutoCorrect && mHasDictionary;
130417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
1305b5d17e52fcda39d540822e615bfb7ed5074e0034satok                pickedDefault = pickDefaultSuggestion(primaryCode);
1306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13104ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1311863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mJustAddedMagicSpace) {
131217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1313863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1314863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                swapSwapperAndSpace();
1315863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            } else {
131617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (mSettingsValues.isMagicSpaceStripper(primaryCode)) removeTrailingSpace();
1317863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1318863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                mJustAddedMagicSpace = false;
1319863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            }
13200730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        } else {
13210730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendKeyChar((char)primaryCode);
13224ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13234ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1324863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1325863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            maybeDoubleSpace();
1326863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1327863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1328b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) primaryCode, true, x, y);
132989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1330979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
133155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
133255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
133355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
1334b2707856aba4fc9b063f26305f1fb603b19c1701satok                InputConnectionCompatUtils.commitCorrection(
133589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
133655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
133755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
133855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
133989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
134089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (Keyboard.CODE_SPACE == primaryCode) {
134189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isCursorTouchingWord()) {
134289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateSuggestions();
134389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateOldSuggestions();
1344cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.postUpdateBigramPredictions();
134589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
134689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
134789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Set punctuation right away. onUpdateSelection will fire but tests whether it is
134889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // already displayed or not, so it's okay.
134955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1350923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1351b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1352923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1354923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1356466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1359b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleClose();
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
13611679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
13621679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
13631679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1364923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
13667a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isSuggestionsRequested() {
1367c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1368c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1370a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
13717a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingPunctuationList() {
137217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSuggestPuncList == mCandidateView.getSuggestions();
13737599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
13747599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
13757a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingSuggestionsStrip() {
13767599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
13777599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
13787599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
13797599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
13807599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
13819fbfd5877305ed19a20663630b498b6b3fdae942satok    public boolean isCandidateStripVisible() {
1382b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1383b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1384952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
13859fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
13869fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
13879fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
13889fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
13899fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
13909fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1391923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1392923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1393409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1394060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1395060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1396060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1397060efb6d82af1f896d90cb845c8ae07c726f85e1satok        View v = mKeyboardSwitcher.getInputView();
1398060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1399060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1400060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1401060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1402060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
14035a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1404060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1405060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1406060efb6d82af1f896d90cb845c8ae07c726f85e1satok        setCandidatesViewShown(isCandidateStripVisible());
1407060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1408060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1409466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1410466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1411409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1413466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1414466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1416b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.getAndResetIsShowingHint()) {
1417466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1418466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1419466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1420466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
14217e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
14229ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
14239ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
14249ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
14259ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1426466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1427466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1428466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1429409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
14319fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1432b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                && !mVoiceProxy.isVoiceInputHighlighted()) {
1433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1434923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1435466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1436f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
1437ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1438923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1439923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1440979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1441979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1442979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1443979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
14449f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: May need a better way of retrieving previous word
1445e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
144617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
14477e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
14489ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1449923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14506f99d12b0752ecdbceda7e5fddead214f939f533Tadashi G. Takaoka        boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
1451a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1452bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Here, we want to promote a whitelisted word if exists.
1453bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
1454bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
1455979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1456979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
14594a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1460979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1461952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        correctionAvailable &= !TextEntryState.isRecorrecting();
1462979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1463a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1464a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1465f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1466f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1467f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1468f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1469f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1470a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
14719fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
14729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
14739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
147417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (previousSuggestions == mSettingsValues.mSuggestPuncList)
14759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
14769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
14779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
14787e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1479979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
14804a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
14819fbfd5877305ed19a20663630b498b6b3fdae942satok    public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
14827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
14837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
148414e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
148582411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
148682411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
14877e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1490923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1492923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1494ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1497b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private boolean pickDefaultSuggestion(int separatorCode) {
1498923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1499d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1500d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1502923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15036780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1504b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord, separatorCode);
1505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
150655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
15079468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1508bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1509979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1510923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1511979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1514923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
15157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
151617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
151717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
15184f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1519952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        final boolean recorrecting = TextEntryState.isRecorrecting();
15209a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
15219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
15229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
15239a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
15241b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
15251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
15261b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1529923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1533923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1534b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
15359a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15369a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
15379a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15406a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
15416a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
154217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0))
154317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) {
1544979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1545979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1546979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
15477e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
1548863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // Find out whether the previous character is a space. If it is, as a special case
1549863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // for punctuation entered through the suggestion strip, it should be considered
1550863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a magic space even if it was a normal space. This is meant to help in case the user
1551863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // pressed space on purpose of displaying the suggestion strip punctuation.
155255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1553863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            final int toLeft = (ic == null) ? 0 : ic.getTextBeforeCursor(1, 0).charAt(0);
15544f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            final boolean oldMagicSpace = mJustAddedMagicSpace;
1555863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true;
1556a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1557a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1558a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
15594f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            mJustAddedMagicSpace = oldMagicSpace;
15609a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15619a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
15629a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
15636a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
15646a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
1565f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
156689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // If we are not composing a word, then it was a suggestion inferred from
156789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // context - no user input. We should reset the word composer.
156889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            mWord.reset();
156989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
15709a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
157155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
15729468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
15730c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1574bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1575979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1576bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToOnlyBigramDictionary(suggestion, 1);
15770c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1578979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
15797e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1580923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1581923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
15820730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        if (mShouldInsertMagicSpace && !recorrecting) {
15830730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendMagicSpace();
1584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1585979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
15867f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We should show the hint if the user pressed the first entry AND either:
15877f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
15887f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        //   AND mHasDictionary is false)
15897f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
15907f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
15917f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
15927f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
15937f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
1594bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
1595bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                // If there is no dictionary the hint should be shown.
1596bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                && (!mHasDictionary
1597bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        // If "suggestion" is not in the dictionary, the hint should be shown.
1598bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        || !AutoCorrection.isValidWord(
1599bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                                mSuggest.getUnigramDictionaries(), suggestion, true));
1600b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1601952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!recorrecting) {
1602b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1603b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1604b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1605b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
1606b5d17e52fcda39d540822e615bfb7ed5074e0034satok                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1607777118a40a363ccab69a00016d3156066513cb78Jean Chalard        }
1608777118a40a363ccab69a00016d3156066513cb78Jean Chalard        if (!showingAddToDictionaryHint) {
1609364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1610979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1611b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1612d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1613979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1614b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
161566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
161666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16179a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16189a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16199a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1620923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1621a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1622979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1623979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1624979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1625979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1626979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1627979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
162855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1629b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1630b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
16311679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1632923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1633923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
163417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mVoiceProxy.rememberReplacedWord(suggestion, mSettingsValues.mWordSeparators);
1635979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1636923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1637f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok        mRecorrection.saveRecorrectionSuggestion(mWord, suggestion);
1638f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
1639923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1640923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1641923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
164289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    private static final WordComposer sEmptyWordComposer = new WordComposer();
1643cb3320179d39a7983874697a0aa428b127675c9dJean Chalard    private void updateBigramPredictions() {
164489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (mSuggest == null || !isSuggestionsRequested())
164589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            return;
164689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
164717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mBigramPredictionEnabled) {
1648cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            setPunctuationSuggestions();
1649cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            return;
1650cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        }
1651cb3320179d39a7983874697a0aa428b127675c9dJean Chalard
165289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
165317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
165489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
165589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mKeyboardSwitcher.getInputView(), sEmptyWordComposer, prevWord);
165689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
165789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (builder.size() > 0) {
165889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Explicitly supply an empty typed word (the no-second-arg version of
165989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // showSuggestions will retrieve the word near the cursor, we don't want that here)
166089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            showSuggestions(builder.build(), "");
166189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
166289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isShowingPunctuationList()) setPunctuationSuggestions();
166389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
166489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    }
166589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
16667a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setPunctuationSuggestions() {
166717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        setSuggestions(mSettingsValues.mSuggestPuncList);
16689fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
16696a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
16706a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1671bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) {
1672979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1673979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1674979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1675bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1676979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1677979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1678979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1679979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1680979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1681bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
1682979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1683979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1684bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            boolean selectedANotTypedWord) {
1685979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
1686bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
16870c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
16880c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
16890c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1690979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1691979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1692979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1693979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1694bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
1695bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean selectedATypedWordAndItsInAutoDic =
1696bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                !selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion);
1697bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean isValidWord = AutoCorrection.isValidWord(
1698bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), suggestion, true);
1699bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic
1700bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                || !isValidWord;
1701bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        if (needsToAddToAutoDictionary) {
1702e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1703e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1704979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1705e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1706863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // We don't want to register as bigrams words separated by a separator.
1707863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // For example "I will, and you too" : we don't want the pair ("will" "and") to be
1708863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a bigram.
1709e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
171017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mWordSeparators);
1711e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1712e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1713979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
171432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
171532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
171632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
17177a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isCursorTouchingWord() {
1718923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1719923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1720923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1721923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
172317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toLeft.charAt(0))
172417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) {
1725923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1726923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1727a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
172817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toRight.charAt(0))
172917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) {
1730923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1732923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1734a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1735dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1736dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1737dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1738dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1739dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1740923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1741923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
1742f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars && length > 0) {
1743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1744504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1746923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1747504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
174817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (!TextUtils.isEmpty(toTheLeft)
174917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && mSettingsValues.isWordSeparator(toTheLeft.charAt(0))) {
1750923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1751923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1752923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
175330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
175430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
175530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
175617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && !TextUtils.isEmpty(punctuation)
175717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && mSettingsValues.isWordSeparator(punctuation.charAt(0))
175830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1759504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1760504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
176130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
1762b5d17e52fcda39d540822e615bfb7ed5074e0034satok                TextEntryState.typedCharacter(punctuation.charAt(0), true,
1763b5d17e52fcda39d540822e615bfb7ed5074e0034satok                        WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
176430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
176530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1766504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
1767f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
1768504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1769504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1770504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1771cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1772d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1773923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1774923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1775923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1776923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1777923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1778923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
177917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.isWordSeparator(code);
1780923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1781923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17820730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private void sendMagicSpace() {
1783571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
17840730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = true;
1785b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1786923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1787923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1788923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
17890b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1790923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1791923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
179288fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
1793c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1794c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
17954ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1796cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
1797b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(),
1798b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.isVoiceButtonOnPrimary());
17990ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
180017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
18014b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
180236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
180336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
180488fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
180588fc9d44186120f9edc5cf7ec0e2af85260fed04satok    private void toggleLanguage(boolean next) {
180688fc9d44186120f9edc5cf7ec0e2af85260fed04satok        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
180788fc9d44186120f9edc5cf7ec0e2af85260fed04satok            mSubtypeSwitcher.toggleLanguage(next);
180888fc9d44186120f9edc5cf7ec0e2af85260fed04satok        }
180917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // The following is necessary because on API levels < 10, we don't get notified when
181017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // subtype changes.
181117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        onRefreshKeyboard();
181217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard     }
181388fc9d44186120f9edc5cf7ec0e2af85260fed04satok
18145a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
18158aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
181617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mSwipeDownDismissKeyboardEnabled)
1817363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1819923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18205a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1821e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPress(int primaryCode, boolean withSliding) {
1822cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1823cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1824cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1825cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
18261679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
18271679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1828571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1829e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onPressShift(withSliding);
1830e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
18316c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
183240a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
18336c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1834681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18375a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1838e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onRelease(int primaryCode, boolean withSliding) {
18391679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
18403f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
18411679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1842571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1843e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onReleaseShift(withSliding);
1844e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
18456c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
184640a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1848a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1849a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1850123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
1851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1854123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
1855123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
1856123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
1857123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1858123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
1859123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
1860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
1864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
1865923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
186917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
1870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1872923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
1874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
1875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
1876923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1877979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mKeyboardSwitcher.getInputView() != null) {
1878923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
1879923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
188117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (isSoundOn()) {
1882923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
1883923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
1884923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
1885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
1886571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
1887923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
1888923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1889571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
1890923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
1891923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1892571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
1893923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
1894923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1895923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1896923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
1897923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1900409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
190117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mVibrateOn) {
1902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
19041679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
19051679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
19061679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
1907979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
190866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
1909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
191271c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public void promoteToUserDictionary(String word, int frequency) {
191334386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
191434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
191534386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
191634386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
191771c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
19186516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
19196516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
19206516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
192117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    boolean isSoundOn() {
192217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSoundOn && !mSilentModeOn;
1923979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1924979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1925e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
19269f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: cleanup messy flags
1927e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
192817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        final boolean shouldAutoCorrect = (mSettingsValues.mAutoCorrectEnabled
192917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                || mSettingsValues.mQuickFixes) && !mInputTypeNoAutoCorrect && mHasDictionary;
193017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled)
1931e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
193217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
193317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect
193417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && mSettingsValues.mAutoCorrectEnabled)
1935979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
1936e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
1937e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
1938e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
1939e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
1940e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
19410ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
194232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
194317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mSuggest.setQuickFixesEnabled(mSettingsValues.mQuickFixes
19444ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
194532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
194632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
194717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) {
19487599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
19499502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
1950458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
19517599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
1952458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
19537599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
19547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
19557599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
19567599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
19577599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
19587599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1959466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
19609502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
1961466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1962466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1963bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
19649502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
1965bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
1966bf96661d33d0126adb60a48880ceba1ff055d4a4satok
1967507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
1968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
1969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
1970466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
1971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
1973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19752fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
197685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
197785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
197885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
197985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
198085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
198185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
198285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
19832fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
19842fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
19852fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
19862fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
198785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
19882cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
19892cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
19902fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
19912fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
19922fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
19932fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
1994aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
1995aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
1996aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
19972fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
19982fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
199985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
200085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
20012fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20032fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
200485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
200585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
200685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
200785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
200885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
200985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
20105a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
201485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2015ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
20162fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
201785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2018ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
20192fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
202285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
202385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
20242fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
20252fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
202685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
202785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
202818e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        final IBinder windowToken = mKeyboardSwitcher.getInputView().getWindowToken();
202918e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        if (windowToken == null) return;
20302fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
20312fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
20322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
20332fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
203485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
203585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2036923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2037a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2038923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2039923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
204018e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        lp.token = windowToken;
2041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2044923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2045923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20477e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
20487e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2049923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2050a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2051923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2052923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2054923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
20559fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
2057f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        p.println("  mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
205817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
20590730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        p.println("  mShouldInsertMagicSpace=" + mShouldInsertMagicSpace);
20601b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2061923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
206217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mSoundOn=" + mSettingsValues.mSoundOn);
206317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mVibrateOn=" + mSettingsValues.mVibrateOn);
2064240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        p.println("  mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
2065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
20666e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2067923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2068a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2070923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2072923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2073a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2074923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2075923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2078923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2079923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2080923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2081923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2082923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2083923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2085