LatinIME.java revision 66a787b953d703201c6b827abbee74e8cd9bb063
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Copyright (C) 2008-2009 Google Inc.
3a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
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
19960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsovimport com.android.inputmethod.voice.EditingUtil;
20960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsovimport com.android.inputmethod.voice.FieldContext;
21960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsovimport com.android.inputmethod.voice.SettingsUtil;
22960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsovimport com.android.inputmethod.voice.VoiceInput;
23466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport com.google.android.collect.Lists;
24388ce92ab8a635c5ad44620dad59baf05dfea510Amith Yamasani
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
3336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.Keyboard;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.KeyboardView;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Vibrator;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
44960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsovimport android.speech.RecognitionManager;
456e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasaniimport android.text.AutoText;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.ClipboardManager;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
5166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
53466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.LayoutInflater;
54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
59466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
60466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedTextRequest;
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputMethodManager;
63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
64466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
65466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
66466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.ArrayList;
67466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.HashMap;
68466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.List;
69466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
70466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Map;
71466741d8a78965b8509bf527344f289e50873092Mike LeBeau
72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
73923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
75466741d8a78965b8509bf527344f289e50873092Mike LeBeaupublic class LatinIME extends InputMethodService
7636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        implements KeyboardView.OnKeyboardActionListener,
77466741d8a78965b8509bf527344f289e50873092Mike LeBeau        VoiceInput.UiListener,
78466741d8a78965b8509bf527344f289e50873092Mike LeBeau        SharedPreferences.OnSharedPreferenceChangeListener {
79466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String TAG = "LatinIME";
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    static final boolean DEBUG = false;
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    static final boolean TRACE = false;
82466741d8a78965b8509bf527344f289e50873092Mike LeBeau    static final boolean VOICE_INSTALLED = true;
83466741d8a78965b8509bf527344f289e50873092Mike LeBeau    static final boolean ENABLE_VOICE_BUTTON = true;
84a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
85923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final String PREF_VIBRATE_ON = "vibrate_on";
86923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final String PREF_SOUND_ON = "sound_on";
87923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final String PREF_AUTO_CAP = "auto_cap";
886e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private static final String PREF_QUICK_FIXES = "quick_fixes";
896e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
906e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private static final String PREF_AUTO_COMPLETE = "auto_complete";
91457fdffce4550b5597435f030483dcafffecf714Amith Yamasani    private static final String PREF_VOICE_MODE = "voice_mode";
92b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani
93466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // Whether or not the user has used voice input before (and thus, whether to show the
94a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    // first-run warning dialog or not).
95466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String PREF_HAS_USED_VOICE_INPUT = "has_used_voice_input";
96a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
97466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // Whether or not the user has used voice input from an unsupported locale UI before.
98466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // For example, the user has a Chinese UI but activates voice input.
99466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE =
100466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "has_used_voice_input_unsupported_locale";
101466741d8a78965b8509bf527344f289e50873092Mike LeBeau
102466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // A list of locales which are supported by default for voice input, unless we get a
103466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // different list from Gservices.
104466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
105466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en " +
106466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_US " +
107466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_GB " +
108466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_AU " +
109466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_CA " +
110466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_IE " +
111466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_IN " +
112466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_NZ " +
113466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_SG " +
114466741d8a78965b8509bf527344f289e50873092Mike LeBeau            "en_ZA ";
115a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
116466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // The private IME option used to indicate that no microphone should be shown for a
117466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // given text field. For instance this is specified by the search dialog when the
118466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // dialog is already showing a voice search button.
119466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String IME_OPTION_NO_MICROPHONE = "nm";
120a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
12236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    public static final String PREF_INPUT_LANGUAGE = "input_language";
123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int MSG_UPDATE_SUGGESTIONS = 0;
1256e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private static final int MSG_START_TUTORIAL = 1;
1264a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    private static final int MSG_UPDATE_SHIFT_STATE = 2;
127466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final int MSG_VOICE_RESULTS = 3;
128466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final int MSG_START_LISTENING_AFTER_SWIPE = 4;
129466741d8a78965b8509bf527344f289e50873092Mike LeBeau
130466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // If we detect a swipe gesture within N ms of typing, then swipe is
131466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // ignored, since it may in fact be two key presses in quick succession.
132466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final long MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE = 1000;
133466741d8a78965b8509bf527344f289e50873092Mike LeBeau
134466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // If we detect a swipe gesture, and the user types N ms later, cancel the
135466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // swipe since it was probably a false trigger.
136466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final long MIN_MILLIS_AFTER_SWIPE_TO_WAIT_FOR_TYPING = 500;
137a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
141d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
142d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    // Weight added to a user picking a new word from the suggestion strip
143d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    static final int FREQUENCY_FOR_PICKED = 3;
144d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    // Weight added to a user typing a new word that doesn't get corrected (or is reverted)
145d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    static final int FREQUENCY_FOR_TYPED = 1;
146d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    // A word that is frequently typed and get's promoted to the user dictionary, uses this
147d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    // frequency.
148d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    static final int FREQUENCY_FOR_AUTO_ADD = 250;
149a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
150d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    static final int KEYCODE_ENTER = '\n';
151d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    static final int KEYCODE_SPACE = ' ';
152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Contextual menu positions
154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int POS_SETTINGS = 0;
155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int POS_METHOD = 1;
156466741d8a78965b8509bf527344f289e50873092Mike LeBeau
157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private LatinKeyboardView mInputView;
158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateViewContainer mCandidateViewContainer;
159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CompletionInfo[] mCompletions;
162a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
164466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private AlertDialog mVoiceWarningDialog;
165a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1666e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    KeyboardSwitcher mKeyboardSwitcher;
167a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
1692bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
17034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    private ExpandableDictionary mAutoDictionary;
17136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
172466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private Hints mHints;
173a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
17436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    Resources mResources;
17536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mLocale;
1773f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani    private LanguageSwitcher mLanguageSwitcher;
178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private StringBuilder mComposing = new StringBuilder();
180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCommittedLength;
182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mPredicting;
183466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mRecognizing;
184466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mAfterVoiceInput;
185466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mImmediatelyAfterVoiceInput;
186466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mShowingVoiceSuggestions;
187466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mImmediatelyAfterVoiceSuggestions;
188466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mVoiceInputHighlighted;
189466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mEnableVoiceButton;
190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
191923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mPredictionOn;
192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mCompletionOn;
193e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoSpace;
195e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mCapsLock;
198466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mPasswordText;
199466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mEmailText;
200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
201923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
2036e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
204466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mHasUsedVoiceInput;
205466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mHasUsedVoiceInputUnsupportedLocale;
206466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mLocaleSupportedForVoiceInput;
2076e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mShowSuggestions;
208466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mSuggestionShouldReplaceCurrentWord;
209466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mIsShowingHint;
2106e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private int     mCorrectionMode;
211466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean mEnableVoice = true;
212b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani    private boolean mVoiceOnPrimary;
213b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private int     mOrientation;
2146a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private List<CharSequence> mSuggestPuncList;
215a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mJustRevertedSeparator;
219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
221a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Tutorial mTutorial;
223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
2252296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
2262296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    private final float FX_VOLUME = -1.0f;
227923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mWordSeparators;
230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mSentenceSeparators;
231466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private VoiceInput mVoiceInput;
232466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private VoiceResults mVoiceResults = new VoiceResults();
233466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private long mSwipeTriggerTimeMillis;
234466741d8a78965b8509bf527344f289e50873092Mike LeBeau
235466741d8a78965b8509bf527344f289e50873092Mike LeBeau    // For each word, a list of potential replacements, usually from voice.
23666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    private Map<String, List<CharSequence>> mWordToSuggestions =
23766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            new HashMap<String, List<CharSequence>>();
238466741d8a78965b8509bf527344f289e50873092Mike LeBeau
239466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private class VoiceResults {
240466741d8a78965b8509bf527344f289e50873092Mike LeBeau        List<String> candidates;
241466741d8a78965b8509bf527344f289e50873092Mike LeBeau        Map<String, List<CharSequence>> alternatives;
242466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
24336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    private boolean mRefreshKeyboardRequired;
24436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    Handler mHandler = new Handler() {
246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                case MSG_UPDATE_SUGGESTIONS:
250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    updateSuggestions();
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2526e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                case MSG_START_TUTORIAL:
2536e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    if (mTutorial == null) {
2546e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                        if (mInputView.isShown()) {
2556e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                            mTutorial = new Tutorial(LatinIME.this, mInputView);
2566e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                            mTutorial.start();
2576e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                        } else {
2586e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                            // Try again soon if the view is not yet showing
2596e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                            sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
2606e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                        }
261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    }
262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani                case MSG_UPDATE_SHIFT_STATE:
2644a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani                    updateShiftKeyState(getCurrentInputEditorInfo());
2654a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani                    break;
266466741d8a78965b8509bf527344f289e50873092Mike LeBeau                case MSG_VOICE_RESULTS:
267466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    handleVoiceResults();
268466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    break;
269466741d8a78965b8509bf527344f289e50873092Mike LeBeau                case MSG_START_LISTENING_AFTER_SWIPE:
270466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    if (mLastKeyTime < mSwipeTriggerTimeMillis) {
271466741d8a78965b8509bf527344f289e50873092Mike LeBeau                        startListening(true);
272466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    }
273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override public void onCreate() {
278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //setStatusIcon(R.drawable.ime_qwerty);
28036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        mResources = getResources();
28136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        final Configuration conf = mResources.getConfiguration();
2823f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
2833f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mLanguageSwitcher = new LanguageSwitcher(this);
2843f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mLanguageSwitcher.loadLocales(prefs);
2853f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mKeyboardSwitcher = new KeyboardSwitcher(this, this);
2863f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
2873f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        boolean enableMultipleLanguages = mLanguageSwitcher.getLocaleCount() > 0;
2883f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        String inputLanguage = mLanguageSwitcher.getInputLanguage();
2893f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        if (inputLanguage == null) {
2903f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            inputLanguage = conf.locale.toString();
2913f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        }
2923f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        initSuggest(inputLanguage);
293b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        mOrientation = conf.orientation;
2946a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
295b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // register to receive ringer mode changes for silent mode
297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
299466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED) {
300466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput = new VoiceInput(this, this);
301466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mHints = new Hints(this, new Hints.Display() {
302466741d8a78965b8509bf527344f289e50873092Mike LeBeau                public void showHint(int viewResource) {
303466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    LayoutInflater inflater = (LayoutInflater) getSystemService(
304466741d8a78965b8509bf527344f289e50873092Mike LeBeau                            Context.LAYOUT_INFLATER_SERVICE);
305466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    View view = inflater.inflate(viewResource, null);
306466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    setCandidatesView(view);
307466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    setCandidatesViewShown(true);
308466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    mIsShowingHint = true;
309466741d8a78965b8509bf527344f289e50873092Mike LeBeau                }
310466741d8a78965b8509bf527344f289e50873092Mike LeBeau              });
311466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
3123f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        prefs.registerOnSharedPreferenceChangeListener(this);
313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
31436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void initSuggest(String locale) {
316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLocale = locale;
31736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
31836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        Resources orig = getResources();
31936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        Configuration conf = orig.getConfiguration();
32036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        Locale saveLocale = conf.locale;
32136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        conf.locale = new Locale(locale);
32236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        orig.updateConfiguration(conf, orig.getDisplayMetrics());
32336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
32436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
32536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest = new Suggest(this, R.raw.main);
327d8564506124fe6a683ef0adf8ca5cf5348756f8dMike LeBeau        if (mUserDictionary != null) mUserDictionary.close();
328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary = new UserDictionary(this);
32936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mContactsDictionary == null) {
33036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mContactsDictionary = new ContactsDictionary(this);
33136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
33236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        // TODO: Save and restore the dictionary for the current input language.
33336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mAutoDictionary == null) {
33436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mAutoDictionary = new AutoDictionary(this);
33536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
3372bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
33834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
339e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
34036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        mWordSeparators = mResources.getString(R.string.word_separators);
34136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        mSentenceSeparators = mResources.getString(R.string.sentence_separators);
34236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
34336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        conf.locale = saveLocale;
34436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        orig.updateConfiguration(conf, orig.getDisplayMetrics());
345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
34636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
347466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
348466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
349923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.close();
3502bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mContactsDictionary.close();
351923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
352466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED) {
353466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.destroy();
354466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
356923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
359923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.equals(conf.locale.toString(), mLocale)) {
361923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            initSuggest(conf.locale.toString());
362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
363b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
364b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
365466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
366466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
367466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
368b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
369b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
37036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        reloadKeyboards();
371923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
372923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
373b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mInputView = (LatinKeyboardView) getLayoutInflater().inflate(
377923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                R.layout.input, null);
378923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mKeyboardSwitcher.setInputView(mInputView);
37912e582c79c4e8028bb03971377633440aa95cefbAmith Yamasani        mKeyboardSwitcher.makeKeyboards(true);
380923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mInputView.setOnKeyboardActionListener(this);
381466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mKeyboardSwitcher.setKeyboardMode(
382466741d8a78965b8509bf527344f289e50873092Mike LeBeau                KeyboardSwitcher.MODE_TEXT, 0,
383466741d8a78965b8509bf527344f289e50873092Mike LeBeau                shouldShowVoiceButton(makeFieldContext(), getCurrentInputEditorInfo()));
384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mInputView;
385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
388466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onInitializeInterface() {
389466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // Create a new view associated with voice input if the old
390466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // view is stuck in another layout (e.g. if switching from
391466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // portrait to landscape while speaking)
392466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // NOTE: This must be done here because for some reason
393466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // onCreateInputView isn't called after an orientation change while
394466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // speech rec is in progress.
395466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mVoiceInput != null && mVoiceInput.getView().getParent() != null) {
396466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.newView();
397466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
398466741d8a78965b8509bf527344f289e50873092Mike LeBeau
399466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onInitializeInterface();
400466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
401466741d8a78965b8509bf527344f289e50873092Mike LeBeau
402466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
403923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
40412e582c79c4e8028bb03971377633440aa95cefbAmith Yamasani        mKeyboardSwitcher.makeKeyboards(true);
405923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateViewContainer = (CandidateViewContainer) getLayoutInflater().inflate(
406923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                R.layout.candidates, null);
407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateViewContainer.initViews();
408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView = (CandidateView) mCandidateViewContainer.findViewById(R.id.candidates);
409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
410923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mCandidateViewContainer;
412923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
414a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mInputView == null) {
418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
42136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mRefreshKeyboardRequired) {
42236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = false;
4233f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            toggleLanguage(true, true);
42436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
42536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
42612e582c79c4e8028bb03971377633440aa95cefbAmith Yamasani        mKeyboardSwitcher.makeKeyboards(false);
4276c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.newSession(this);
4296c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
430466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // Most such things we decide below in the switch statement, but we need to know
431466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // now whether this is a password text field, because we need to know now (before
432466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // the switch statement) whether we want to enable the voice button.
433466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mPasswordText = false;
434466741d8a78965b8509bf527344f289e50873092Mike LeBeau        int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
435466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
436466741d8a78965b8509bf527344f289e50873092Mike LeBeau                variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
437466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mPasswordText = true;
438466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
439a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
440466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mEnableVoiceButton = shouldShowVoiceButton(makeFieldContext(), attribute);
441b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani        final boolean enableVoiceButton = mEnableVoiceButton && mEnableVoice;
442466741d8a78965b8509bf527344f289e50873092Mike LeBeau
443466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mAfterVoiceInput = false;
444466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mImmediatelyAfterVoiceInput = false;
445466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mShowingVoiceSuggestions = false;
446466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mImmediatelyAfterVoiceSuggestions = false;
447466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInputHighlighted = false;
448466741d8a78965b8509bf527344f289e50873092Mike LeBeau        boolean disableAutoCorrect = false;
449466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mWordToSuggestions.clear();
450e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPredictionOn = false;
452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCompletionOn = false;
453923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCompletions = null;
454923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCapsLock = false;
455466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mEmailText = false;
456466741d8a78965b8509bf527344f289e50873092Mike LeBeau        switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case EditorInfo.TYPE_CLASS_NUMBER:
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case EditorInfo.TYPE_CLASS_DATETIME:
459e3803800c53cc813e27dd1e7c31bdb4d075f0252Amith Yamasani                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_SYMBOLS,
460b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                        attribute.imeOptions, enableVoiceButton);
461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
462923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case EditorInfo.TYPE_CLASS_PHONE:
463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_PHONE,
464b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                        attribute.imeOptions, enableVoiceButton);
465923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
466923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case EditorInfo.TYPE_CLASS_TEXT:
467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
468b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                        attribute.imeOptions, enableVoiceButton);
469923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                //startPrediction();
470923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mPredictionOn = true;
471923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Make sure that passwords are not displayed in candidate view
472923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) {
474923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPredictionOn = false;
475923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
476466741d8a78965b8509bf527344f289e50873092Mike LeBeau                if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
477466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    mEmailText = true;
478466741d8a78965b8509bf527344f289e50873092Mike LeBeau                }
479923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        || variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) {
481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = false;
482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = true;
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPredictionOn = false;
487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_EMAIL,
488b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                            attribute.imeOptions, enableVoiceButton);
489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
490923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPredictionOn = false;
491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_URL,
492b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                            attribute.imeOptions, enableVoiceButton);
493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
494923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_IM,
495b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                            attribute.imeOptions, enableVoiceButton);
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPredictionOn = false;
4986c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
499cf02653097893b06f24551b790b0f7ec288e704dAmith Yamasani                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_WEB,
500b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                            attribute.imeOptions, enableVoiceButton);
5016c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // If it's a browser edit field and auto correct is not ON explicitly, then
5026c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // disable auto correction, but keep suggestions on.
5036c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
504e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                        mInputTypeNoAutoCorrect = true;
5056c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    }
506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
50736ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani
50836ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If NO_SUGGESTIONS is set, don't do prediction.
50936ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
51036ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                    mPredictionOn = false;
511e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
51236ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
51336ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If it's not multiline and the autoCorrect flag is not set, then don't correct
51436ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
51536ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                        (attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
516e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
51736ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPredictionOn = false;
520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mCompletionOn = true && isFullscreenMode();
521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateShiftKeyState(attribute);
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            default:
525923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
526b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                        attribute.imeOptions, enableVoiceButton);
527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateShiftKeyState(attribute);
528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
529923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mInputView.closing();
530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mComposing.setLength(0);
531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPredicting = false;
532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mDeleteCount = 0;
533923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        loadSettings();
534e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
535466741d8a78965b8509bf527344f289e50873092Mike LeBeau        setCandidatesViewShown(false);
536466741d8a78965b8509bf527344f289e50873092Mike LeBeau        setSuggestions(null, false, false, false);
537466741d8a78965b8509bf527344f289e50873092Mike LeBeau
538466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // Override auto correct
539466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (disableAutoCorrect) {
540466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mAutoCorrectOn = false;
541466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (mCorrectionMode == Suggest.CORRECTION_FULL) {
542466741d8a78965b8509bf527344f289e50873092Mike LeBeau                mCorrectionMode = Suggest.CORRECTION_BASIC;
543466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
544466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
545e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        // If the dictionary is not big enough, don't auto correct
546e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest.hasMainDictionary();
547e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
548e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
549e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
5506e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        mInputView.setProximityCorrectionEnabled(true);
551a200a9bff75130b1d79d505c6770f3132f8499bdAmith Yamasani        mPredictionOn = mPredictionOn && mCorrectionMode > 0;
5526e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        checkTutorial(attribute.privateImeOptions);
5534a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
555923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
556923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
557923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
558923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
559a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
5601322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen        if (VOICE_INSTALLED && mAfterVoiceInput) {
5611322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen            mVoiceInput.logInputEnded();
5621322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen        }
563a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
5641322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen        if (VOICE_INSTALLED) {
5651322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen            mVoiceInput.flushLogs();
5661322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen        }
567a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
568923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mInputView != null) {
569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mInputView.closing();
570923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
5711322b7f899e9d3ccfb91d9e3ede99b3ad336c354Kristian Monsen        if (VOICE_INSTALLED && mRecognizing) {
572466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.cancel();
573466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
574466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
575466741d8a78965b8509bf527344f289e50873092Mike LeBeau
576466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
577466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
578466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
579466741d8a78965b8509bf527344f289e50873092Mike LeBeau        InputConnection ic = getCurrentInputConnection();
580466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
581466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.logTextModified();
582466741d8a78965b8509bf527344f289e50873092Mike LeBeau
583466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (mHints.showPunctuationHintIfNecessary(ic)) {
584466741d8a78965b8509bf527344f289e50873092Mike LeBeau                mVoiceInput.logPunctuationHintDisplayed();
585466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
586466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
587466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mImmediatelyAfterVoiceInput = false;
588923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
589923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
590923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
591923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
592923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
593923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
596466741d8a78965b8509bf527344f289e50873092Mike LeBeau
597466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
598466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
599466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
600466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
601466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
602466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
603466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
604466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
605466741d8a78965b8509bf527344f289e50873092Mike LeBeau
606466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mSuggestionShouldReplaceCurrentWord = false;
607923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
608923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
609466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if ((((mComposing.length() > 0 && mPredicting) || mVoiceInputHighlighted)
610466741d8a78965b8509bf527344f289e50873092Mike LeBeau                && (newSelStart != candidatesEnd
611466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    || newSelEnd != candidatesEnd))) {
612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mPredicting = false;
614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
619923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
620466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInputHighlighted = false;
621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (!mPredicting && !mJustAccepted
622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && TextEntryState.getState() == TextEntryState.STATE_ACCEPTED_DEFAULT) {
623923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
624923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
6263263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani        postUpdateShiftKeyState();
627466741d8a78965b8509bf527344f289e50873092Mike LeBeau
628466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED) {
629466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (mShowingVoiceSuggestions) {
630466741d8a78965b8509bf527344f289e50873092Mike LeBeau                if (mImmediatelyAfterVoiceSuggestions) {
631466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    mImmediatelyAfterVoiceSuggestions = false;
632466741d8a78965b8509bf527344f289e50873092Mike LeBeau                } else {
633466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    updateSuggestions();
634466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    mShowingVoiceSuggestions = false;
635466741d8a78965b8509bf527344f289e50873092Mike LeBeau                }
636466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
637466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (VoiceInput.ENABLE_WORD_CORRECTIONS) {
638466741d8a78965b8509bf527344f289e50873092Mike LeBeau                // If we have alternatives for the current word, then show them.
639466741d8a78965b8509bf527344f289e50873092Mike LeBeau                String word = EditingUtil.getWordAtCursor(
640466741d8a78965b8509bf527344f289e50873092Mike LeBeau                        getCurrentInputConnection(), getWordSeparators());
641466741d8a78965b8509bf527344f289e50873092Mike LeBeau                if (word != null && mWordToSuggestions.containsKey(word.trim())) {
642466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    mSuggestionShouldReplaceCurrentWord = true;
643466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    final List<CharSequence> suggestions = mWordToSuggestions.get(word.trim());
644466741d8a78965b8509bf527344f289e50873092Mike LeBeau
645466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    setSuggestions(suggestions, false, true, true);
646466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    setCandidatesViewShown(true);
647466741d8a78965b8509bf527344f289e50873092Mike LeBeau                }
648466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
649466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
650923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
651923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
652923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
654466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mAfterVoiceInput) mVoiceInput.logInputEnded();
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
6566e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
6576e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
6586e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
6596e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
660466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
661466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.logKeyboardWarningDialogDismissed();
662466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceWarningDialog.dismiss();
663466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceWarningDialog = null;
664466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
6656e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mTutorial != null) {
6666e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mTutorial.close();
667a200a9bff75130b1d79d505c6770f3132f8499bdAmith Yamasani            mTutorial = null;
668a200a9bff75130b1d79d505c6770f3132f8499bdAmith Yamasani        }
669466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED & mRecognizing) {
670466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.cancel();
671466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
673923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
674923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
675923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onDisplayCompletions(CompletionInfo[] completions) {
678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (false) {
679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            Log.i("foo", "Received completions:");
680923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            for (int i=0; i<(completions != null ? completions.length : 0); i++) {
681923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                Log.i("foo", "  #" + i + ": " + completions[i]);
682923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
683923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
684923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCompletionOn) {
685923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCompletions = completions;
686923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (completions == null) {
687466741d8a78965b8509bf527344f289e50873092Mike LeBeau                setSuggestions(null, false, false, false);
688923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
689923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
690a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
691923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            List<CharSequence> stringList = new ArrayList<CharSequence>();
692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            for (int i=0; i<(completions != null ? completions.length : 0); i++) {
693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                CompletionInfo ci = completions[i];
694923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (ci != null) stringList.add(ci.getText());
695923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
696923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            //CharSequence typedWord = mWord.getTypedWord();
697466741d8a78965b8509bf527344f289e50873092Mike LeBeau            setSuggestions(stringList, true, true, true);
698923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
701923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
702923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
703923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void setCandidatesViewShown(boolean shown) {
705923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // TODO: Remove this if we support candidates with hard keyboard
706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            super.setCandidatesViewShown(shown);
708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
710a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
713923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
714264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        if (!isFullscreenMode()) {
715264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project            outInsets.contentTopInsets = outInsets.visibleTopInsets;
716264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        }
717923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
718a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
719923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
720923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
721923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case KeyEvent.KEYCODE_BACK:
723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (event.getRepeatCount() == 0 && mInputView != null) {
724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    if (mInputView.handleBack()) {
725923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        return true;
7266e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    } else if (mTutorial != null) {
7276e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                        mTutorial.close();
7286e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                        mTutorial = null;
729923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    }
730923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
7326e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            case KeyEvent.KEYCODE_DPAD_DOWN:
7336e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            case KeyEvent.KEYCODE_DPAD_UP:
7346e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            case KeyEvent.KEYCODE_DPAD_LEFT:
7356e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            case KeyEvent.KEYCODE_DPAD_RIGHT:
7366e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                // If tutorial is visible, don't allow dpad to work
7376e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                if (mTutorial != null) {
7386e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
7396e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
7406e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                break;
741923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
742923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
744923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
746923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
747923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
748923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_DOWN:
749923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_UP:
750923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_LEFT:
751923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case KeyEvent.KEYCODE_DPAD_RIGHT:
7526e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                // If tutorial is visible, don't allow dpad to work
7536e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                if (mTutorial != null) {
7546e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
7556e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
756923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Enable shift key and DPAD to do selections
757923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mInputView != null && mInputView.isShown() && mInputView.isShifted()) {
758a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker                    event = new KeyEvent(event.getDownTime(), event.getEventTime(),
759923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                            event.getAction(), event.getKeyCode(), event.getRepeatCount(),
760923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                            event.getDeviceId(), event.getScanCode(),
761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                            KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    InputConnection ic = getCurrentInputConnection();
763923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    if (ic != null) ic.sendKeyEvent(event);
764923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    return true;
765923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
766923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
767923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
768923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
769923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
770923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
771466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void revertVoiceInput() {
772466741d8a78965b8509bf527344f289e50873092Mike LeBeau        InputConnection ic = getCurrentInputConnection();
773466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (ic != null) ic.commitText("", 1);
774466741d8a78965b8509bf527344f289e50873092Mike LeBeau        updateSuggestions();
775466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInputHighlighted = false;
776466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
777466741d8a78965b8509bf527344f289e50873092Mike LeBeau
778466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void commitVoiceInput() {
779466741d8a78965b8509bf527344f289e50873092Mike LeBeau        InputConnection ic = getCurrentInputConnection();
780466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (ic != null) ic.finishComposingText();
781466741d8a78965b8509bf527344f289e50873092Mike LeBeau        updateSuggestions();
782466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInputHighlighted = false;
783466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
784466741d8a78965b8509bf527344f289e50873092Mike LeBeau
78536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    private void reloadKeyboards() {
78636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mKeyboardSwitcher == null) {
78736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mKeyboardSwitcher = new KeyboardSwitcher(this, this);
78836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
7893f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
790b8f98ad014ac6f1d453128f902dba67ebebff1d3Amith Yamasani        if (mInputView != null) {
791b8f98ad014ac6f1d453128f902dba67ebebff1d3Amith Yamasani            mKeyboardSwitcher.setVoiceMode(mEnableVoice, mVoiceOnPrimary);
792b8f98ad014ac6f1d453128f902dba67ebebff1d3Amith Yamasani        }
79336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        mKeyboardSwitcher.makeKeyboards(true);
79436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
79536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
796923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void commitTyped(InputConnection inputConnection) {
797923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mPredicting) {
798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mPredicting = false;
799923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
800923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
805d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani                mAutoDictionary.addWord(mComposing.toString(), FREQUENCY_FOR_TYPED);
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
808923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
810923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
8113263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani    private void postUpdateShiftKeyState() {
8123263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani        mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
8133263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SHIFT_STATE), 300);
8143263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani    }
8153263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani
816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void updateShiftKeyState(EditorInfo attr) {
817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (attr != null && mInputView != null && mKeyboardSwitcher.isAlphabetMode()
819923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && ic != null) {
8201c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani            mInputView.setShifted(mCapsLock || getCursorCapsMode(ic, attr) != 0);
821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
8231c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
8241c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    private int getCursorCapsMode(InputConnection ic, EditorInfo attr) {
8251c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        int caps = 0;
8261c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
8271c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
8281c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani            caps = ic.getCursorCapsMode(attr.inputType);
8291c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
8301c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        return caps;
8311c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
8321c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void swapPunctuationAndSpace() {
834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
838923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && lastTwo.charAt(0) == KEYCODE_SPACE && isSentenceSeparator(lastTwo.charAt(1))) {
839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
841923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
842923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateShiftKeyState(getCurrentInputEditorInfo());
844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
8461c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void doubleSpace() {
848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //if (!mAutoPunctuate) return;
849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && lastThree.charAt(1) == KEYCODE_SPACE && lastThree.charAt(2) == KEYCODE_SPACE) {
856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateShiftKeyState(getCurrentInputEditorInfo());
861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
863a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
86441a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
86541a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
86641a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
86741a519729505a877844f2c57a33509c302dddbceKen Wakasa
86841a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
86941a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
87041a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
87141a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (lastOne != null && lastOne.length() == 1 && lastOne.charAt(0) == '.'
87241a519729505a877844f2c57a33509c302dddbceKen Wakasa                && text.charAt(0) == '.') {
87341a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
87441a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
87541a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
87641a519729505a877844f2c57a33509c302dddbceKen Wakasa
877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
878923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
879923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
881923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
882923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
883923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
884923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
887923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
888923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
889a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
890923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Implementation of KeyboardViewListener
891923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
892923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onKey(int primaryCode, int[] keyCodes) {
893923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
894a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (primaryCode != Keyboard.KEYCODE_DELETE ||
895923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                when > mLastKeyTime + QUICK_PRESS) {
896923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
897923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
900923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case Keyboard.KEYCODE_DELETE:
901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                handleBackspace();
902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mDeleteCount++;
903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case Keyboard.KEYCODE_SHIFT:
905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                handleShift();
906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
907923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case Keyboard.KEYCODE_CANCEL:
908923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mOptionsDialog == null || !mOptionsDialog.isShowing()) {
909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    handleClose();
910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case LatinKeyboardView.KEYCODE_OPTIONS:
913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                showOptionsMenu();
914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
9158eb2e34d5b2def57c9548f88e37e5c9e5a0bea59Amith Yamasani            case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE:
9163f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani                toggleLanguage(false, true);
9173f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani                break;
9183f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            case LatinKeyboardView.KEYCODE_PREV_LANGUAGE:
9193f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani                toggleLanguage(false, false);
92036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani                break;
921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case LatinKeyboardView.KEYCODE_SHIFT_LONGPRESS:
922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mCapsLock) {
923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    handleShift();
924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    toggleCapsLock();
926923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
927923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
928923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            case Keyboard.KEYCODE_MODE_CHANGE:
929923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                changeKeyboardMode();
930923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
931466741d8a78965b8509bf527344f289e50873092Mike LeBeau            case LatinKeyboardView.KEYCODE_VOICE:
932466741d8a78965b8509bf527344f289e50873092Mike LeBeau                if (VOICE_INSTALLED) {
933466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    startListening(false /* was a button press, was not a swipe */);
934466741d8a78965b8509bf527344f289e50873092Mike LeBeau                }
935466741d8a78965b8509bf527344f289e50873092Mike LeBeau                break;
936cf02653097893b06f24551b790b0f7ec288e704dAmith Yamasani            case 9 /*Tab*/:
9378fa317a61a2152347c59dda7eb1b8e2979f6cc1dLeon Scroggins                sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
938cf02653097893b06f24551b790b0f7ec288e704dAmith Yamasani                break;
939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            default:
940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (isWordSeparator(primaryCode)) {
941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    handleSeparator(primaryCode);
942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
943923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    handleCharacter(primaryCode, keyCodes);
944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Cancel the just reverted state
946923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mJustRevertedSeparator = null;
947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
948b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (mKeyboardSwitcher.onKey(primaryCode)) {
949b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            changeKeyboardMode();
950b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
952a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onText(CharSequence text) {
954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mPredicting) {
958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            commitTyped(ic);
959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
96041a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
963923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateShiftKeyState(getCurrentInputEditorInfo());
964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustRevertedSeparator = null;
965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
968466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
969466741d8a78965b8509bf527344f289e50873092Mike LeBeau            revertVoiceInput();
970466741d8a78965b8509bf527344f289e50873092Mike LeBeau            return;
971466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean deleteChar = false;
973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
975923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mPredicting) {
976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPredicting = false;
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                postUpdateSuggestions();
985923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
986923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
987923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
9913263841911dc3dbbf4ffe26d2f046e38a1896f72Amith Yamasani        postUpdateShiftKeyState();
992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TextEntryState.getState() == TextEntryState.STATE_UNDO_COMMIT) {
994923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
998923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mDeleteCount > DELETE_ACCELERATE_AT) {
999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1000923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustRevertedSeparator = null;
1003923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1004923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleShift() {
100682c68bfbfc9442ebb7d8be842aaf8dedf5ffc76eAmith Yamasani        mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
1007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mKeyboardSwitcher.isAlphabetMode()) {
1008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // Alphabet keyboard
1009923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            checkToggleCapsLock();
1010923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mInputView.setShifted(mCapsLock || !mInputView.isShifted());
1011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mKeyboardSwitcher.toggleShift();
1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1015a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleCharacter(int primaryCode, int[] keyCodes) {
1017466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
1018466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitVoiceInput();
1019466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (isAlphabet(primaryCode) && isPredictionOn() && !isCursorTouchingWord()) {
1021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (!mPredicting) {
1022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mPredicting = true;
1023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1026923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1027923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mInputView.isShifted()) {
102856f96fe05b2b01c488ce569eb2eefc13ee917fd3Amith Yamasani            // TODO: This doesn't work with ß, need to fix it in the next release.
1029eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1030eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1031eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1032eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
103356f96fe05b2b01c488ce569eb2eefc13ee917fd3Amith Yamasani            primaryCode = new String(keyCodes, 0, 1).toUpperCase().charAt(0);
1034923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1035923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mPredicting) {
1036923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mInputView.isShifted() && mComposing.length() == 0) {
1037923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.setCapitalized(true);
1038923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1039923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.append((char) primaryCode);
1040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mWord.add(primaryCode, keyCodes);
1041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
10431c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
10441c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
10451c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                    mWord.setAutoCapitalized(
10461c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                            getCursorCapsMode(ic, getCurrentInputEditorInfo()) != 0);
10471c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1048923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1049923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1050923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            postUpdateSuggestions();
1051923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1052923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendKeyChar((char)primaryCode);
1053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
10548850bdc7e4c1da7049231bc1e21f17213562f9b6Amith Yamasani        updateShiftKeyState(getCurrentInputEditorInfo());
1055923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        measureCps();
1056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode));
1057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleSeparator(int primaryCode) {
1060466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
1061466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitVoiceInput();
1062466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1063923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
1065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1066923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1067923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1068923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mPredicting) {
1070923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1071a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1072923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1073923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1074a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            if (mAutoCorrectOn && primaryCode != '\'' &&
1075a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker                    (mJustRevertedSeparator == null
1076a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker                            || mJustRevertedSeparator.length() == 0
1077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                            || mJustRevertedSeparator.charAt(0) != primaryCode)) {
1078923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                pickDefaultSuggestion();
1079923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                pickedDefault = true;
1080923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1081923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1082923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1083923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)primaryCode);
1085923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) primaryCode, true);
1086a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED
1087923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && primaryCode != KEYCODE_ENTER) {
1088923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            swapPunctuationAndSpace();
1089a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        } else if (isPredictionOn() && primaryCode == ' ') {
1090923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //else if (TextEntryState.STATE_SPACE_AFTER_ACCEPTED) {
1091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            doubleSpace();
1092923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1093923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (pickedDefault && mBestWord != null) {
1094923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
1095923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateShiftKeyState(getCurrentInputEditorInfo());
1097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1101466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1104466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED & mRecognizing) {
1105466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mVoiceInput.cancel();
1106466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
1108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mInputView.closing();
1109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
1110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void checkToggleCapsLock() {
1113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mInputView.getKeyboard().isShifted()) {
1114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            toggleCapsLock();
1115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1117a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void toggleCapsLock() {
1119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCapsLock = !mCapsLock;
1120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mKeyboardSwitcher.isAlphabetMode()) {
1121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ((LatinKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock);
1122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void postUpdateSuggestions() {
1126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
1127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100);
1128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1129a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isPredictionOn() {
1131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean predictionOn = mPredictionOn;
1132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //if (isFullscreenMode()) predictionOn &= mPredictionLandscape;
1133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return predictionOn;
1134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1135a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1136923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCandidateStripVisible() {
11376e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        return isPredictionOn() && mShowSuggestions;
1138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1140466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onCancelVoice() {
1141466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mRecognizing) {
1142466741d8a78965b8509bf527344f289e50873092Mike LeBeau            switchToKeyboardView();
1143466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1144466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1145466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1146466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void switchToKeyboardView() {
1147466741d8a78965b8509bf527344f289e50873092Mike LeBeau      mHandler.post(new Runnable() {
1148466741d8a78965b8509bf527344f289e50873092Mike LeBeau          public void run() {
1149466741d8a78965b8509bf527344f289e50873092Mike LeBeau              mRecognizing = false;
1150466741d8a78965b8509bf527344f289e50873092Mike LeBeau              if (mInputView != null) {
1151466741d8a78965b8509bf527344f289e50873092Mike LeBeau                setInputView(mInputView);
1152466741d8a78965b8509bf527344f289e50873092Mike LeBeau              }
1153466741d8a78965b8509bf527344f289e50873092Mike LeBeau              updateInputViewShown();
1154466741d8a78965b8509bf527344f289e50873092Mike LeBeau          }});
1155466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1156466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1157466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void switchToRecognitionStatusView() {
1158466741d8a78965b8509bf527344f289e50873092Mike LeBeau      mHandler.post(new Runnable() {
1159466741d8a78965b8509bf527344f289e50873092Mike LeBeau          public void run() {
1160466741d8a78965b8509bf527344f289e50873092Mike LeBeau              mRecognizing = true;
1161466741d8a78965b8509bf527344f289e50873092Mike LeBeau              setInputView(mVoiceInput.getView());
1162466741d8a78965b8509bf527344f289e50873092Mike LeBeau              updateInputViewShown();
1163466741d8a78965b8509bf527344f289e50873092Mike LeBeau          }});
1164466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1165466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1166466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void startListening(boolean swipe) {
1167466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (!mHasUsedVoiceInput ||
1168466741d8a78965b8509bf527344f289e50873092Mike LeBeau                (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale)) {
1169466741d8a78965b8509bf527344f289e50873092Mike LeBeau            // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
1170466741d8a78965b8509bf527344f289e50873092Mike LeBeau            showVoiceWarningDialog(swipe);
1171466741d8a78965b8509bf527344f289e50873092Mike LeBeau        } else {
1172466741d8a78965b8509bf527344f289e50873092Mike LeBeau            reallyStartListening(swipe);
1173466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1174466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1175a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1176466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void reallyStartListening(boolean swipe) {
1177466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (!mHasUsedVoiceInput) {
1178466741d8a78965b8509bf527344f289e50873092Mike LeBeau            // The user has started a voice input, so remember that in the
1179466741d8a78965b8509bf527344f289e50873092Mike LeBeau            // future (so we don't show the warning dialog after the first run).
1180466741d8a78965b8509bf527344f289e50873092Mike LeBeau            SharedPreferences.Editor editor =
1181466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    PreferenceManager.getDefaultSharedPreferences(this).edit();
1182466741d8a78965b8509bf527344f289e50873092Mike LeBeau            editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
1183466741d8a78965b8509bf527344f289e50873092Mike LeBeau            editor.commit();
1184466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mHasUsedVoiceInput = true;
1185466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1186a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1187466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale) {
1188466741d8a78965b8509bf527344f289e50873092Mike LeBeau            // The user has started a voice input from an unsupported locale, so remember that
1189466741d8a78965b8509bf527344f289e50873092Mike LeBeau            // in the future (so we don't show the warning dialog the next time they do this).
1190466741d8a78965b8509bf527344f289e50873092Mike LeBeau            SharedPreferences.Editor editor =
1191466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    PreferenceManager.getDefaultSharedPreferences(this).edit();
1192466741d8a78965b8509bf527344f289e50873092Mike LeBeau            editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
1193466741d8a78965b8509bf527344f289e50873092Mike LeBeau            editor.commit();
1194466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mHasUsedVoiceInputUnsupportedLocale = true;
1195466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1196a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1197466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // Clear N-best suggestions
1198466741d8a78965b8509bf527344f289e50873092Mike LeBeau        setSuggestions(null, false, false, true);
1199466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1200466741d8a78965b8509bf527344f289e50873092Mike LeBeau        FieldContext context = new FieldContext(
12012e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau            getCurrentInputConnection(),
12022e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau            getCurrentInputEditorInfo(),
12032e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau            mLanguageSwitcher.getInputLanguage(),
12042e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau            mLanguageSwitcher.getEnabledLanguages());
1205466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInput.startListening(context, swipe);
1206466741d8a78965b8509bf527344f289e50873092Mike LeBeau        switchToRecognitionStatusView();
1207466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1208a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1209466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void showVoiceWarningDialog(final boolean swipe) {
1210466741d8a78965b8509bf527344f289e50873092Mike LeBeau        AlertDialog.Builder builder = new AlertDialog.Builder(this);
1211466741d8a78965b8509bf527344f289e50873092Mike LeBeau        builder.setCancelable(true);
1212466741d8a78965b8509bf527344f289e50873092Mike LeBeau        builder.setIcon(R.drawable.ic_mic_dialog);
1213466741d8a78965b8509bf527344f289e50873092Mike LeBeau        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
1214466741d8a78965b8509bf527344f289e50873092Mike LeBeau            public void onClick(DialogInterface dialog, int whichButton) {
1215466741d8a78965b8509bf527344f289e50873092Mike LeBeau                mVoiceInput.logKeyboardWarningDialogOk();
1216466741d8a78965b8509bf527344f289e50873092Mike LeBeau                reallyStartListening(swipe);
1217466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1218466741d8a78965b8509bf527344f289e50873092Mike LeBeau        });
1219466741d8a78965b8509bf527344f289e50873092Mike LeBeau        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
1220466741d8a78965b8509bf527344f289e50873092Mike LeBeau            public void onClick(DialogInterface dialog, int whichButton) {
1221466741d8a78965b8509bf527344f289e50873092Mike LeBeau                mVoiceInput.logKeyboardWarningDialogCancel();
1222466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1223466741d8a78965b8509bf527344f289e50873092Mike LeBeau        });
1224a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1225466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mLocaleSupportedForVoiceInput) {
1226466741d8a78965b8509bf527344f289e50873092Mike LeBeau            String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" +
1227466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    getString(R.string.voice_warning_how_to_turn_off);
1228466741d8a78965b8509bf527344f289e50873092Mike LeBeau            builder.setMessage(message);
1229466741d8a78965b8509bf527344f289e50873092Mike LeBeau        } else {
1230466741d8a78965b8509bf527344f289e50873092Mike LeBeau            String message = getString(R.string.voice_warning_locale_not_supported) + "\n\n" +
1231466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    getString(R.string.voice_warning_may_not_understand) + "\n\n" +
1232466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    getString(R.string.voice_warning_how_to_turn_off);
1233466741d8a78965b8509bf527344f289e50873092Mike LeBeau            builder.setMessage(message);
1234466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1235a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1236466741d8a78965b8509bf527344f289e50873092Mike LeBeau        builder.setTitle(R.string.voice_warning_title);
1237466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceWarningDialog = builder.create();
1238a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1239466741d8a78965b8509bf527344f289e50873092Mike LeBeau        Window window = mVoiceWarningDialog.getWindow();
1240466741d8a78965b8509bf527344f289e50873092Mike LeBeau        WindowManager.LayoutParams lp = window.getAttributes();
1241466741d8a78965b8509bf527344f289e50873092Mike LeBeau        lp.token = mInputView.getWindowToken();
1242466741d8a78965b8509bf527344f289e50873092Mike LeBeau        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
1243466741d8a78965b8509bf527344f289e50873092Mike LeBeau        window.setAttributes(lp);
1244466741d8a78965b8509bf527344f289e50873092Mike LeBeau        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1245466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInput.logKeyboardWarningDialogShown();
1246466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceWarningDialog.show();
1247466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1248466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1249466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onVoiceResults(List<String> candidates,
1250466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Map<String, List<CharSequence>> alternatives) {
1251466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (!mRecognizing) {
1252466741d8a78965b8509bf527344f289e50873092Mike LeBeau            return;
1253466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1254466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceResults.candidates = candidates;
1255466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceResults.alternatives = alternatives;
1256466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mHandler.sendMessage(mHandler.obtainMessage(MSG_VOICE_RESULTS));
1257466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1258466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1259466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void handleVoiceResults() {
1260466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mAfterVoiceInput = true;
1261466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mImmediatelyAfterVoiceInput = true;
1262466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1263466741d8a78965b8509bf527344f289e50873092Mike LeBeau        InputConnection ic = getCurrentInputConnection();
1264466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (!isFullscreenMode()) {
1265466741d8a78965b8509bf527344f289e50873092Mike LeBeau            // Start listening for updates to the text from typing, etc.
1266466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) {
1267466741d8a78965b8509bf527344f289e50873092Mike LeBeau                ExtractedTextRequest req = new ExtractedTextRequest();
1268466741d8a78965b8509bf527344f289e50873092Mike LeBeau                ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
1269466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1270466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1271466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1272466741d8a78965b8509bf527344f289e50873092Mike LeBeau        vibrate();
1273466741d8a78965b8509bf527344f289e50873092Mike LeBeau        switchToKeyboardView();
1274466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1275466741d8a78965b8509bf527344f289e50873092Mike LeBeau        final List<CharSequence> nBest = new ArrayList<CharSequence>();
1276466741d8a78965b8509bf527344f289e50873092Mike LeBeau        boolean capitalizeFirstWord = preferCapitalization()
1277466741d8a78965b8509bf527344f289e50873092Mike LeBeau                || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted());
1278466741d8a78965b8509bf527344f289e50873092Mike LeBeau        for (String c : mVoiceResults.candidates) {
1279466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (capitalizeFirstWord) {
1280466741d8a78965b8509bf527344f289e50873092Mike LeBeau                c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length());
1281466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1282466741d8a78965b8509bf527344f289e50873092Mike LeBeau            nBest.add(c);
1283466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1284466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1285466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (nBest.size() == 0) {
1286466741d8a78965b8509bf527344f289e50873092Mike LeBeau            return;
1287466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1288466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1289466741d8a78965b8509bf527344f289e50873092Mike LeBeau        String bestResult = nBest.get(0).toString();
1290466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1291466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInput.logVoiceInputDelivered();
1292466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1293466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mHints.registerVoiceResult(bestResult);
1294466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1295466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
1296466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1297466741d8a78965b8509bf527344f289e50873092Mike LeBeau        commitTyped(ic);
1298466741d8a78965b8509bf527344f289e50873092Mike LeBeau        EditingUtil.appendText(ic, bestResult);
1299466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1300466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (ic != null) ic.endBatchEdit();
1301466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1302466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // Show N-Best alternates, if there is more than one choice.
1303466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (nBest.size() > 1) {
1304466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mImmediatelyAfterVoiceSuggestions = true;
1305466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mShowingVoiceSuggestions = true;
1306466741d8a78965b8509bf527344f289e50873092Mike LeBeau            setSuggestions(nBest.subList(1, nBest.size()), false, true, true);
1307466741d8a78965b8509bf527344f289e50873092Mike LeBeau            setCandidatesViewShown(true);
1308466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1309466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mVoiceInputHighlighted = true;
1310466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mWordToSuggestions.putAll(mVoiceResults.alternatives);
1311466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1312466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1313466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1314466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void setSuggestions(
1315466741d8a78965b8509bf527344f289e50873092Mike LeBeau            List<CharSequence> suggestions,
1316466741d8a78965b8509bf527344f289e50873092Mike LeBeau            boolean completions,
1317466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1318466741d8a78965b8509bf527344f289e50873092Mike LeBeau            boolean typedWordValid,
1319466741d8a78965b8509bf527344f289e50873092Mike LeBeau            boolean haveMinimalSuggestion) {
1320466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1321466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mIsShowingHint) {
1322466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1323466741d8a78965b8509bf527344f289e50873092Mike LeBeau             mIsShowingHint = false;
1324466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1325466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1326466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
1327466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mCandidateView.setSuggestions(
1328466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    suggestions, completions, typedWordValid, haveMinimalSuggestion);
1329466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1330466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1331466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateSuggestions() {
1333466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mSuggestionShouldReplaceCurrentWord = false;
1334466741d8a78965b8509bf527344f289e50873092Mike LeBeau
13351b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani        ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null);
13361b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1337923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
1338466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if ((mSuggest == null || !isPredictionOn()) && !mVoiceInputHighlighted) {
1339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1341466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1342923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mPredicting) {
13436a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            setNextSuggestions();
1344923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1347923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, mWord, false);
13481b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani        int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
13491b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
13501b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani        ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(nextLettersFrequencies);
13511b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1352923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean correctionAvailable = mSuggest.hasMinimalCorrection();
1353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //|| mCorrectionMode == mSuggest.CORRECTION_FULL;
1354923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence typedWord = mWord.getTypedWord();
1355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If we're in basic correct
1356f590a497393eb77875017010e9a36cf33b095e3cAmith Yamasani        boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
1357f590a497393eb77875017010e9a36cf33b095e3cAmith Yamasani                (preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
1358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_FULL) {
1359923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13614a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
13624a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        correctionAvailable &= !mWord.isMostlyCaps();
13634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
1364466741d8a78965b8509bf527344f289e50873092Mike LeBeau        setSuggestions(stringList, false, typedWordValid, correctionAvailable);
1365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (stringList.size() > 0) {
1366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (correctionAvailable && !typedWordValid && stringList.size() > 1) {
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = stringList.get(1);
1368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1371923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1372923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1373923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
1375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1377923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void pickDefaultSuggestion() {
1378923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mHandler.hasMessages(MSG_UPDATE_SUGGESTIONS)) {
1380923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
1381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1383923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mBestWord != null) {
1384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
1385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
1386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            pickSuggestion(mBestWord);
1387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1388923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1389923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1390923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
1391466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mAfterVoiceInput && mShowingVoiceSuggestions) mVoiceInput.logNBestChoose(index);
1392466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCompletionOn && mCompletions != null && index >= 0
1394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && index < mCompletions.length) {
1395923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            CompletionInfo ci = mCompletions[index];
1396923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1399923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1401923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1402923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1403923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1404923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateShiftKeyState(getCurrentInputEditorInfo());
1405923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1406923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
14076a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
14086a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
14096a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        if (suggestion.length() == 1 && isWordSeparator(suggestion.charAt(0))) {
14106a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            onKey(suggestion.charAt(0), null);
14116a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
14126a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
1413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        pickSuggestion(suggestion);
1414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAutoSpace) {
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendSpace();
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Fool the state watcher so that a subsequent backspace will not do a revert
1420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
142166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        if (index == 0 && !mSuggest.isValidWord(suggestion)) {
142266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
142366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
1424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1425a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1426923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void pickSuggestion(CharSequence suggestion) {
1427923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCapsLock) {
1428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            suggestion = suggestion.toString().toUpperCase();
1429a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        } else if (preferCapitalization()
1430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted())) {
143156f96fe05b2b01c488ce569eb2eefc13ee917fd3Amith Yamasani            suggestion = suggestion.toString().toUpperCase().charAt(0)
1432923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    + suggestion.subSequence(1, suggestion.length()).toString();
1433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1434923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1435923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1436466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (mSuggestionShouldReplaceCurrentWord) {
1437466741d8a78965b8509bf527344f289e50873092Mike LeBeau                EditingUtil.deleteWordAtCursor(ic, getWordSeparators());
1438466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1439466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (!VoiceInput.DELETE_SYMBOL.equals(suggestion)) {
1440466741d8a78965b8509bf527344f289e50873092Mike LeBeau                ic.commitText(suggestion, 1);
1441466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1442923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
144334386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        // Add the word to the auto dictionary if it's not a known word
144434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mAutoDictionary.isValidWord(suggestion) || !mSuggest.isValidWord(suggestion)) {
1445d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani            mAutoDictionary.addWord(suggestion.toString(), FREQUENCY_FOR_PICKED);
144634386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        }
1447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPredicting = false;
1448923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
14496a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        setNextSuggestions();
1450923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateShiftKeyState(getCurrentInputEditorInfo());
1451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14536a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void setNextSuggestions() {
14546a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        setSuggestions(mSuggestPuncList, false, false, false);
14556a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
14566a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCursorTouchingWord() {
1458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1462923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
1463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && !isWordSeparator(toLeft.charAt(0))) {
1464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1465923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1466a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
1467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && !isWordSeparator(toRight.charAt(0))) {
1468923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1469923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1470923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1471923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1472a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1474923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
1475923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mPredicting && length > 0) {
1476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mPredicting = true;
1478923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1479923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustRevertedSeparator = ic.getTextBeforeCursor(1, 0);
1480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1483a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            if (toTheLeft != null && toTheLeft.length() > 0
1484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    && isWordSeparator(toTheLeft.charAt(0))) {
1485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
1488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.setComposingText(mComposing, 1);
1489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.backspace();
1490923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            postUpdateSuggestions();
1492923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1494923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustRevertedSeparator = null;
1495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1498923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1501a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1502923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
1503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
1504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
1505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isSentenceSeparator(int code) {
1508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mSentenceSeparators.contains(String.valueOf((char)code));
1509923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1510923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1511923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void sendSpace() {
1512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)KEYCODE_SPACE);
1513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateShiftKeyState(getCurrentInputEditorInfo());
1514923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //onKey(KEY_SPACE[0], KEY_SPACE);
1515923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1516923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
1518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWord.isCapitalized();
1519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void swipeRight() {
1522466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (userHasNotTypedRecently() && VOICE_INSTALLED && mEnableVoice &&
1523466741d8a78965b8509bf527344f289e50873092Mike LeBeau                fieldCanDoVoice(makeFieldContext())) {
1524466741d8a78965b8509bf527344f289e50873092Mike LeBeau            startListening(true /* was a swipe */);
1525466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1526466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (LatinKeyboardView.DEBUG_AUTO_PLAY) {
1528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE));
1529923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            CharSequence text = cm.getText();
1530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (!TextUtils.isEmpty(text)) {
1531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mInputView.startPlaying(text.toString());
1532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1533923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
153536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
15363f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani    private void toggleLanguage(boolean reset, boolean next) {
15373f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        if (reset) {
15383f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            mLanguageSwitcher.reset();
15393f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        } else {
15403f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            if (next) {
15413f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani                mLanguageSwitcher.next();
15423f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            } else {
15433f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani                mLanguageSwitcher.prev();
15443f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            }
15453f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        }
154636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        int currentKeyboardMode = mKeyboardSwitcher.getKeyboardMode();
154736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        reloadKeyboards();
154836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        mKeyboardSwitcher.makeKeyboards(true);
1549b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani        mKeyboardSwitcher.setKeyboardMode(currentKeyboardMode, 0,
1550b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                mEnableVoiceButton && mEnableVoice);
15513f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        initSuggest(mLanguageSwitcher.getInputLanguage());
15523f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mLanguageSwitcher.persist();
155336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        updateShiftKeyState(getCurrentInputEditorInfo());
155436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
155536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
155636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
155736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            String key) {
155836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (PREF_SELECTED_LANGUAGES.equals(key)) {
15593f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani            mLanguageSwitcher.loadLocales(sharedPreferences);
156036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = true;
156136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
156236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
156336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1564923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void swipeLeft() {
1565923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1566923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1567923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void swipeDown() {
15685d11ccc27d9e06a174b5f027109e29b34eea751eAmith Yamasani        handleClose();
1569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1570923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1571923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void swipeUp() {
1572923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //launchSettings();
1573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onPress(int primaryCode) {
1576923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        vibrate();
1577923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        playKeyClick(primaryCode);
1578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1579923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1580923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onRelease(int primaryCode) {
15813f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
15823f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        ((LatinKeyboard) mInputView.getKeyboard()).keyReleased();
1583923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //vibrate();
1584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1585a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1586466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private FieldContext makeFieldContext() {
15872e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau        return new FieldContext(
15882e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau                getCurrentInputConnection(),
15892e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau                getCurrentInputEditorInfo(),
15902e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau                mLanguageSwitcher.getInputLanguage(),
15912e3aa86cf389236c085ab4758239b01e80c3b2dcMike LeBeau                mLanguageSwitcher.getEnabledLanguages());
1592466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1593a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1594466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean fieldCanDoVoice(FieldContext fieldContext) {
1595466741d8a78965b8509bf527344f289e50873092Mike LeBeau        return !mPasswordText
1596466741d8a78965b8509bf527344f289e50873092Mike LeBeau                && mVoiceInput != null
1597466741d8a78965b8509bf527344f289e50873092Mike LeBeau                && !mVoiceInput.isBlacklistedField(fieldContext);
1598466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1599466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1600466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean fieldIsRecommendedForVoice(FieldContext fieldContext) {
1601466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // TODO: Move this logic into the VoiceInput method.
1602466741d8a78965b8509bf527344f289e50873092Mike LeBeau        return !mPasswordText && !mEmailText && mVoiceInput.isRecommendedField(fieldContext);
1603466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1604923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1605466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) {
1606960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsov        return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
1607466741d8a78965b8509bf527344f289e50873092Mike LeBeau                && !(attribute != null && attribute.privateImeOptions != null
1608960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsov                        && attribute.privateImeOptions.equals(IME_OPTION_NO_MICROPHONE))
1609960ea65f3f2162e7f8f387380924162d42fef4dcValentin Kravtsov                && RecognitionManager.isRecognitionAvailable(this);
1610466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1611a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // receive ringer mode changes to detect silent mode
1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateRingerMode();
1617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1619923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1620923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
1621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
1622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1623923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1624923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
1626923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
1627923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1628923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1629923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1630466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private boolean userHasNotTypedRecently() {
1631466741d8a78965b8509bf527344f289e50873092Mike LeBeau        return (SystemClock.uptimeMillis() - mLastKeyTime)
1632466741d8a78965b8509bf527344f289e50873092Mike LeBeau            > MIN_MILLIS_AFTER_TYPING_BEFORE_SWIPE;
1633466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1634466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1635466741d8a78965b8509bf527344f289e50873092Mike LeBeau    /*
1636466741d8a78965b8509bf527344f289e50873092Mike LeBeau     * Only trigger a swipe action if the user hasn't typed X millis before
1637466741d8a78965b8509bf527344f289e50873092Mike LeBeau     * now, and if they don't type Y millis after the swipe is detected. This
1638466741d8a78965b8509bf527344f289e50873092Mike LeBeau     * delays the onset of the swipe action by Y millis.
1639466741d8a78965b8509bf527344f289e50873092Mike LeBeau     */
1640466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private void conservativelyTriggerSwipeAction(final Runnable action) {
1641466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (userHasNotTypedRecently()) {
1642466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mSwipeTriggerTimeMillis = System.currentTimeMillis();
1643466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mHandler.sendMessageDelayed(
1644466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    mHandler.obtainMessage(MSG_START_LISTENING_AFTER_SWIPE),
1645466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    MIN_MILLIS_AFTER_SWIPE_TO_WAIT_FOR_TYPING);
1646466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1647466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1648466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1649466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1650923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
1651923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
1652923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
1653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mInputView != null) {
1655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
1656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSoundOn && !mSilentMode) {
1659923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
1660923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
1661923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
1662923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
1663923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                case Keyboard.KEYCODE_DELETE:
1664923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
1665923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1666923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                case KEYCODE_ENTER:
1667923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
1668923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1669923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                case KEYCODE_SPACE:
1670923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
1671923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1673923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
1674923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1675923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void vibrate() {
1678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mVibrateOn) {
1679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1680923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
168166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        if (mInputView != null) {
168266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mInputView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
168366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
1684923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1685923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1686923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
16876e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private void checkTutorial(String privateImeOptions) {
16886e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (privateImeOptions == null) return;
16896e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (privateImeOptions.equals("com.android.setupwizard:ShowTutorial")) {
16906e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            if (mTutorial == null) startTutorial();
16916e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        } else if (privateImeOptions.equals("com.android.setupwizard:HideTutorial")) {
16926e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            if (mTutorial != null) {
16936e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                if (mTutorial.close()) {
16946e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    mTutorial = null;
16956e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
16966e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            }
16976e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
16986e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    }
1699a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
17006e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private void startTutorial() {
17016e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500);
17026e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    }
17036e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
17046e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    void tutorialDone() {
17056e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        mTutorial = null;
17066e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    }
170734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
170834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    void promoteToUserDictionary(String word, int frequency) {
170934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
171034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
171134386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
171234386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
1713e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
1714e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
1715e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
1716e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                && !mInputTypeNoAutoCorrect && mHasDictionary;
1717e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mCorrectionMode = mAutoCorrectOn
1718e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
1719e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                : (mQuickFixes ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
1720e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
1721e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
1722e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
1723e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
1724e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
1725466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
1726466741d8a78965b8509bf527344f289e50873092Mike LeBeau        launchSettings(LatinIMESettings.class);
1727466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1728466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1729466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings(Class settingsClass) {
1730923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
1731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
1732466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
1733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
1735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1736923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1737923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void loadSettings() {
1738923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Get the settings preferences
1739923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
17405ff5160ff89231ceb55d4d248fb529743d3f8e16Amith Yamasani        mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, false);
1741923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSoundOn = sp.getBoolean(PREF_SOUND_ON, false);
1742923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mAutoCap = sp.getBoolean(PREF_AUTO_CAP, true);
17436e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true);
1744466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mHasUsedVoiceInput = sp.getBoolean(PREF_HAS_USED_VOICE_INPUT, false);
1745466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mHasUsedVoiceInputUnsupportedLocale =
1746466741d8a78965b8509bf527344f289e50873092Mike LeBeau                sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false);
1747a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1748466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // Get the current list of supported locales and check the current locale against that
1749466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // list. We cache this value so as not to check it every time the user starts a voice
1750466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // input. Because this method is called by onStartInputView, this should mean that as
1751466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // long as the locale doesn't change while the user is keeping the IME open, the
1752466741d8a78965b8509bf527344f289e50873092Mike LeBeau        // value should never be stale.
1753a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        String supportedLocalesString = SettingsUtil.getSettingsString(
1754466741d8a78965b8509bf527344f289e50873092Mike LeBeau                getContentResolver(),
1755a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker                SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
1756466741d8a78965b8509bf527344f289e50873092Mike LeBeau                DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
1757466741d8a78965b8509bf527344f289e50873092Mike LeBeau        ArrayList<String> voiceInputSupportedLocales =
1758466741d8a78965b8509bf527344f289e50873092Mike LeBeau                Lists.newArrayList(supportedLocalesString.split("\\s+"));
1759a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1760466741d8a78965b8509bf527344f289e50873092Mike LeBeau        mLocaleSupportedForVoiceInput = voiceInputSupportedLocales.contains(mLocale);
1761a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
17626e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        // If there is no auto text data, then quickfix is forced to "on", so that the other options
17636e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        // will continue to work
1764466741d8a78965b8509bf527344f289e50873092Mike LeBeau
17656e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (AutoText.getSize(mInputView) < 1) mQuickFixes = true;
17666e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true) & mQuickFixes;
1767466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1768466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (VOICE_INSTALLED) {
1769457fdffce4550b5597435f030483dcafffecf714Amith Yamasani            final String voiceMode = sp.getString(PREF_VOICE_MODE, "");
1770457fdffce4550b5597435f030483dcafffecf714Amith Yamasani            boolean enableVoice = !voiceMode.equals(getString(R.string.voice_mode_off));
1771457fdffce4550b5597435f030483dcafffecf714Amith Yamasani            boolean voiceOnPrimary = voiceMode.equals(getString(R.string.voice_mode_main));
1772b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani            if (mKeyboardSwitcher != null &&
1773b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                    (enableVoice != mEnableVoice || voiceOnPrimary != mVoiceOnPrimary)) {
1774b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani                mKeyboardSwitcher.setVoiceMode(enableVoice, voiceOnPrimary);
1775466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
1776466741d8a78965b8509bf527344f289e50873092Mike LeBeau            mEnableVoice = enableVoice;
1777b1cd7016028f5770da2688f1ec51e0601fc5b9ebAmith Yamasani            mVoiceOnPrimary = voiceOnPrimary;
1778466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1779e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectEnabled = sp.getBoolean(PREF_AUTO_COMPLETE,
178036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani                mResources.getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions;
1781e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
17823f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        mLanguageSwitcher.loadLocales(sp);
178336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
178436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
17856a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
17866a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        mSuggestPuncList = new ArrayList<CharSequence>();
17876a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        String suggestPuncs = mResources.getString(R.string.suggested_punctuations);
17886a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        if (suggestPuncs != null) {
17896a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            for (int i = 0; i < suggestPuncs.length(); i++) {
17906a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani                mSuggestPuncList.add(suggestPuncs.subSequence(i, i + 1));
17916a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
17926a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
17936a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
17946a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1795923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void showOptionsMenu() {
1796923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        AlertDialog.Builder builder = new AlertDialog.Builder(this);
1797923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setCancelable(true);
1798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setIcon(R.drawable.ic_dialog_keyboard);
1799923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setNegativeButton(android.R.string.cancel, null);
1800923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence itemSettings = getString(R.string.english_ime_settings);
1801466741d8a78965b8509bf527344f289e50873092Mike LeBeau        CharSequence itemInputMethod = getString(R.string.inputMethod);
1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setItems(new CharSequence[] {
1803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                itemSettings, itemInputMethod},
1804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                new DialogInterface.OnClickListener() {
1805923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
1807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
1808923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
1809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    case POS_SETTINGS:
1810923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        launchSettings();
1811923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        break;
1812923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    case POS_METHOD:
181371351469e3af45a2ee89b017089f9e850e973a19Brandon Ballinger                        ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
181471351469e3af45a2ee89b017089f9e850e973a19Brandon Ballinger                            .showInputMethodPicker();
1815923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        break;
1816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        });
181936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        builder.setTitle(mResources.getString(R.string.english_ime_name));
1820923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
1821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
1822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
1823923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.token = mInputView.getWindowToken();
1824923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
1825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
1826923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
1827923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
1828923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1829923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void changeKeyboardMode() {
1831923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mKeyboardSwitcher.toggleSymbols();
1832923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCapsLock && mKeyboardSwitcher.isAlphabetMode()) {
1833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ((LatinKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock);
1834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateShiftKeyState(getCurrentInputEditorInfo());
1837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
183836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
1841a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1842923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
1843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
1844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
1845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCapsLock=" + mCapsLock);
1846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
1847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mPredictionOn=" + mPredictionOn);
1848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
1849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mPredicting=" + mPredicting);
1850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
1851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoSpace=" + mAutoSpace);
1852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCompletionOn=" + mCompletionOn);
1853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
1854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
1855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
1856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
18576e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
1859a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final boolean PERF_DEBUG = false;
1861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
1862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
1863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
1864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
1865e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mInputTypeNoAutoCorrect;
1866a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
1868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!LatinIME.PERF_DEBUG) return;
1869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
1870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
1871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
1872923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
1873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
1874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
1875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
1876923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
1877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
187834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
187934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    class AutoDictionary extends ExpandableDictionary {
1880d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani        // If the user touches a typed word 2 times or more, it will become valid.
1881d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani        private static final int VALIDITY_THRESHOLD = 2 * FREQUENCY_FOR_PICKED;
1882d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani        // If the user touches a typed word 5 times or more, it will be added to the user dict.
18836a442663d600fa1d8cc0b7a77f313b0a13a4b809Amith Yamasani        private static final int PROMOTION_THRESHOLD = 4 * FREQUENCY_FOR_PICKED;
188434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
188534386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        public AutoDictionary(Context context) {
188634386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani            super(context);
188734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        }
188834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
188934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        @Override
189034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        public boolean isValidWord(CharSequence word) {
189134386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani            final int frequency = getWordFrequency(word);
18926a442663d600fa1d8cc0b7a77f313b0a13a4b809Amith Yamasani            return frequency >= VALIDITY_THRESHOLD;
189334386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        }
189434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
189534386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        @Override
1896d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani        public void addWord(String word, int addFrequency) {
189781115075d28e7df6b43fd2252b83211ba2a827deAmith Yamasani            final int length = word.length();
189881115075d28e7df6b43fd2252b83211ba2a827deAmith Yamasani            // Don't add very short or very long words.
189981115075d28e7df6b43fd2252b83211ba2a827deAmith Yamasani            if (length < 2 || length > getMaxWordLength()) return;
19001c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani            if (mWord.isAutoCapitalized()) {
19011c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // Remove caps before adding
19021c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                word = Character.toLowerCase(word.charAt(0))
19031c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                        + word.substring(1);
19041c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani            }
19056a442663d600fa1d8cc0b7a77f313b0a13a4b809Amith Yamasani            int freq = getWordFrequency(word);
19066a442663d600fa1d8cc0b7a77f313b0a13a4b809Amith Yamasani            freq = freq < 0 ? addFrequency : freq + addFrequency;
19076a442663d600fa1d8cc0b7a77f313b0a13a4b809Amith Yamasani            super.addWord(word, freq);
19086a442663d600fa1d8cc0b7a77f313b0a13a4b809Amith Yamasani            if (freq >= PROMOTION_THRESHOLD) {
1909d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani                LatinIME.this.promoteToUserDictionary(word, FREQUENCY_FOR_AUTO_ADD);
191034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani            }
191134386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        }
191234386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
1913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
1914