LatinIME.java revision 7e9615f218630d14ae5666ede2efd5f12d0a23c3
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
20923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
2736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
30123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
3218e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasaimport android.os.IBinder;
33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
35bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
37e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
39979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
4366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
468e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
478e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
52466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
54c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka
555ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils;
56c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils;
57c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.EditorInfoCompatUtils;
58c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputConnectionCompatUtils;
59c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
60c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
61c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputTypeCompatUtils;
621fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils;
63c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.LanguageSwitcherProxy;
64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.VoiceProxy;
65c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.recorrection.Recorrection;
66c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
67c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
68c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
69c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
70c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
71c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
73466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
74466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
75466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
76466741d8a78965b8509bf527344f289e50873092Mike LeBeau
77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
80c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaokapublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener,
81c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        CandidateView.Listener {
828efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    private static final String TAG = LatinIME.class.getSimpleName();
83979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
84409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
859e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka    private static boolean DEBUG;
86a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
878efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
888efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     *
928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
9410dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok    @SuppressWarnings("dep-ann")
958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
1008efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
1018efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
1024199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1034199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1074199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1084199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1098efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
1109e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
111fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
115d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
116a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
117cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
118cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
119cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
120cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
121cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
122cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1237599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1247599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1257599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1287599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
13717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private Settings.Values mSettingsValues;
13817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
139e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
1407a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka    private int mCandidateStripHeight;
141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
144a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
146a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
147610f1dc8553cf2ed97e763a06a19380c4a6cd636satok    private InputMethodManagerCompatWrapper mImm;
1482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
15171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1520ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
153b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    private VoiceProxy mVoiceProxy;
1547a8dac55278cedd838be325f56b4c52d973c61f5satok    private Recorrection mRecorrection;
155a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
157979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1584ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
15936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1600730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // TODO: Create an inner class to group options and pseudo-options to improve readability.
161c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
1620730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mShouldInsertMagicSpace;
163c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
164c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
165c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
166c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
16771c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
170f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard    private boolean mHasUncommittedTypedChars;
171e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1720730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // Magic space: a space that should disappear on space/apostrophe insertion, move after the
1730730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // punctuation on punctuation insertion, and become a real space on alpha char insertion.
1740730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mJustAddedMagicSpace; // This indicates whether the last char is a magic space.
1754733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // This indicates whether the last keypress resulted in processing of double space replacement
1764733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // with period-space.
1774733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private boolean mJustReplacedDoubleSpace;
178409220583333bdf06290dd9fd42f91b5c0d1b11asatok
17979efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
18079efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
18179efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
182979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
18379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
18479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
185979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1864733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't
1874733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // "expect" it, it means the user actually moved the cursor.
1884733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private boolean mExpectingUpdateSelection;
189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
191a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
1932296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
19471c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
19517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private boolean mSilentModeOn; // System-wide current configuration
196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
197b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    // TODO: Move this flag to VoiceProxy
19881c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
199466741d8a78965b8509bf527344f289e50873092Mike LeBeau
200cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
201cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private BroadcastReceiver mDictionaryPackInstallReceiver =
202cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard            new DictionaryPackInstallBroadcastReceiver(this);
203cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
204dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
205dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
206dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
20736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2084f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public final UIHandler mHandler = new UIHandler(this);
209d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
2104f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
211d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
212d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
213d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
214d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
215de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
216de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
217fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        private static final int MSG_SPACE_TYPED = 6;
218cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
219d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
2204f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UIHandler(LatinIME outerInstance) {
2214f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
2224f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
2234f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
2264f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinIME latinIme = getOuterInstance();
2274f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
228c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getKeyboardView();
229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
230d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
2314f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.updateSuggestions();
232d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
233d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
2344f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.mRecorrection.fetchAndDisplayRecorrectionSuggestions(
2354f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mVoiceProxy, latinIme.mCandidateView,
2364f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWord,
2374f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mHasUncommittedTypedChars, latinIme.mLastSelectionStart,
2384f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mLastSelectionEnd, latinIme.mSettingsValues.mWordSeparators);
239d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
240d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
241de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
242d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
243cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            case MSG_SET_BIGRAM_PREDICTIONS:
2444f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.updateBigramPredictions();
24589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                break;
246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
2474f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization()
248de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
249de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
250de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
25117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
25266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
2534f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            (1.0f + latinIme.mSettingsValues.
2544f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                                    mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
25566432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
25617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
257de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
2584f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mSettingsValues.mDurationOfFadeoutLanguageOnSpacebar);
259de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
260de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
26117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
26266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
2634f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
26417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            (LatinKeyboard)msg.obj);
26517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
267923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
269d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
270d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
271d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
2729b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS),
2734f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
274d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
275d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
276d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
277d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
278d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
279d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
280d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
283d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
2874f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateOldSuggestions);
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
294d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
295d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
29617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
2974f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateShiftState);
298d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
299d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
300d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
302d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
304cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void postUpdateBigramPredictions() {
305cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
3069b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS),
3074f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
30889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
30989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
310cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void cancelUpdateBigramPredictions() {
311cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
31289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
31389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
317de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
318d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
3194f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinIME latinIme = getOuterInstance();
320de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
321de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
3224f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView();
323de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
3244f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard();
325c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The language is always displayed when the delay is negative.
326c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                final boolean needsToDisplayLanguage = localeChanged
3274f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        || latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar < 0;
328de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
3294f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                if (latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar != 0) {
330c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
3314f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            : latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
3324f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            keyboard);
33317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
334c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The fadeout animation will start when the delay is positive.
3354f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                if (localeChanged
3364f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        && latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar > 0) {
337de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
3384f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar);
339de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
340de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
341de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
342fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
343fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void startDoubleSpacesTimer() {
344fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
345fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
3464f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDoubleSpacesTurnIntoPeriodTimeout);
347fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
348fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
349fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void cancelDoubleSpacesTimer() {
350fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
351fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
352fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
353fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public boolean isAcceptingDoubleSpaces() {
354fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            return hasMessages(MSG_SPACE_TYPED);
355fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
356d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3587e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3597e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
36027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
36127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
36227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
3636d9021527a38ba1e94225020389621a0d7227aa1satok        LanguageSwitcherProxy.init(this, prefs);
36427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
36527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
3667a8dac55278cedd838be325f56b4c52d973c61f5satok        Recorrection.init(this, prefs);
3675ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette        AccessibilityUtils.init(this, prefs);
368363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
370363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
371610f1dc8553cf2ed97e763a06a19380c4a6cd636satok        mImm = InputMethodManagerCompatWrapper.getInstance(this);
3728efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
3730ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3740ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
3757a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection = Recorrection.getInstance();
3769e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka        DEBUG = LatinImeLogger.sDBG;
377363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
37817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
37917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
380363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
381363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
382fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
3839502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
384979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
3859502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
386979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
3870ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
388979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
389979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
3909502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
391979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
392979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
393979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
394363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
395b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
396cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Register to receive ringer mode change and network state change.
397cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Also receive installation and removal of a dictionary pack.
398123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
399123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
400123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
401923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
402b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
403cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
404cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final IntentFilter packageFilter = new IntentFilter();
405cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
406cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
407cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addDataScheme(SCHEME_PACKAGE);
408cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
409646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard
410646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        final IntentFilter newDictFilter = new IntentFilter();
411646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        newDictFilter.addAction(
412646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard                DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
413646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
41536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
41617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    // Has to be package-visible for unit tests
41717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    /* package */ void loadSettings() {
41817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
41917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
42017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
421699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard        resetContactsDictionary();
42217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    }
42317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
4240ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
425cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
426eaa10f44a4a0108a90803b1b28238842d3fb5addsatok        final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr);
42736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
428309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Resources res = mResources;
429309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
43036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
43136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
43236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
433979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4348efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
435cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
43617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCorrectEnabled) {
43717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
43817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        }
43927023341658b4cf5430d18ddb94fd9502ecfe3cbTadashi G. Takaoka        updateAutoTextEnabled();
440e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
441cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserDictionary = new UserDictionary(this, localeStr);
442923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
443e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
444699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard        resetContactsDictionary();
445e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
446cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mAutoDictionary = new AutoDictionary(this, this, localeStr, Suggest.DIC_AUTO);
44734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
448e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
449cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserBigramDictionary = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER);
450e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
451e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
452e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
45336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
454309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        Utils.setSystemLocale(res, savedLocale);
455923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
45636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
457699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard    private void resetContactsDictionary() {
458699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard        if (null == mSuggest) return;
459699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard        ContactsDictionary contactsDictionary = mSettingsValues.mUseContactsDict
460699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard                ? new ContactsDictionary(this, Suggest.DIC_CONTACTS) : null;
461699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard        mSuggest.setContactsDictionary(contactsDictionary);
462699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard    }
463699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard
464cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /* package private */ void resetSuggestMainDict() {
465cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
466eaa10f44a4a0108a90803b1b28238842d3fb5addsatok        final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr);
467cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
468cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
469cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
470cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
471466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
472466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
473e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
474e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
475e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
476979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
478cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
479b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.destroy();
480979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
481979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
487dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
488b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
489b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
490466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
491466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
492466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
493b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
4942fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
4952fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
496b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
4978b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
49881c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
500b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.onConfigurationChanged(conf);
50181c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
50288fc9d44186120f9edc5cf7ec0e2af85260fed04satok
50388fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
50488fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.onConfigurationChanged(conf);
505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
506b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
5096c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
5106c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    }
5116c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka
5126c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    @Override
5136c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    public void setInputView(View view) {
5146c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        super.setInputView(view);
5156c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        mCandidateViewContainer = view.findViewById(R.id.candidates_container);
5166c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        mCandidateView = (CandidateView) view.findViewById(R.id.candidates);
517281e180c33b1dd88e8eae48f279736c529f529d2Tadashi G. Takaoka        if (mCandidateView != null)
518281e180c33b1dd88e8eae48f279736c529f529d2Tadashi G. Takaoka            mCandidateView.setListener(this, view);
519c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height);
520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
523c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    public void setCandidatesView(View view) {
524c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        // To ensure that CandidatesView will never be set.
525c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return;
526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
528a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
529923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
53045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
531c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getKeyboardView();
5328e09172df1bb176cc899940862c56bed9b9aec4esatok
53389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (DEBUG) {
534f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka            Log.d(TAG, "onStartInputView: attribute:" + ((attribute == null) ? "none"
535f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka                    : String.format("inputType=0x%08x imeOptions=0x%08x",
536f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka                            attribute.inputType, attribute.imeOptions)));
537910b73127fa207dd26ec8124000262523b0aac0csatok        }
538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
539979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
542923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5438d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5444ab730dbd34fad323063f2ffd31ce33de746668dsatok
545662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        TextEntryState.reset();
5466c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
547c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
548c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
549c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
550b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        final VoiceProxy voiceIme = mVoiceProxy;
551e9957752bcaad048746c7a57bbd2c0a59e1918a0satok        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(attribute.inputType)
552e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                || InputTypeCompatUtils.isVisiblePasswordInputType(attribute.inputType));
553c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
554cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
555c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
556c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
557c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
558c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
559f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
560c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
5610730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
5624733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mJustReplacedDoubleSpace = false;
563c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
56417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
56517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateCorrectionMode();
56617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateAutoTextEnabled();
56717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateSuggestionVisibility(mPrefs, mResources);
56817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
56917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
57017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
57117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard         }
57217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.loadSettings(attribute, mPrefs);
57317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // This will work only when the subtype is not supported.
57417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        LanguageSwitcherProxy.loadSettings();
57517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
576c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
577cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            switcher.loadKeyboard(attribute,
5784503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    mSubtypeSwitcher.isShortcutImeEnabled() && voiceIme.isVoiceButtonEnabled(),
5794503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka                    voiceIme.isVoiceButtonOnPrimary());
580c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
581c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
582c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
583c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShownInternal(isCandidateStripVisible(), /* needsInputViewShown */ false);
584c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
585c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
586c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
587c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
588c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
589240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn,
590240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard                mSettingsValues.mKeyPreviewPopupDismissDelay);
591c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
592c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
5937a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.checkRecorrectionOnStart();
594c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
595c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
5964503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka        voiceIme.onStartInputView(inputView.getWindowToken());
597c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
598c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
599c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
600c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
601cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
602cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
603cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
6044b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
605c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
6060730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mShouldInsertMagicSpace = false;
607e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
6089fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
6091b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
6101b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
611dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
612cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
613cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
614cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // Make sure that passwords are not displayed in candidate view
615e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isPasswordInputType(inputType)
616e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
617cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
618cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
619e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)
620cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
6210730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = false;
622cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
6230730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = true;
624cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
625e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)) {
626cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
627cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
628cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
629cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
630cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
631cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
632cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
633cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
634cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
635e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
63636ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
637cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
638cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
639cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
640cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
641cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
642cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
643cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
644cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
645cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
646cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
647cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
648cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
649cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
650cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
651cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
652cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
657e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    public void onWindowHidden() {
658e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        super.onWindowHidden();
659c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
660e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        if (inputView != null) inputView.closing();
661e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    }
662e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
663e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    @Override
664923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
665923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
666a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
667979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6681b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
669979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
670b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
671409220583333bdf06290dd9fd42f91b5c0d1b11asatok
672c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
673d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6744ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
675979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
676466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
677466741d8a78965b8509bf527344f289e50873092Mike LeBeau
678466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
6796495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
6806495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
681c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
682d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
683d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
684d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
685d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
6866495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
6876495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
6886495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
689466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
690466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
691b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.showPunctuationHintIfNecessary();
692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
694923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
695923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
696923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
697923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
698923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
700466741d8a78965b8509bf527344f289e50873092Mike LeBeau
701466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
702466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
703466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
704025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
705025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
706466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
707466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
708466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
709466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
710466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
711466741d8a78965b8509bf527344f289e50873092Mike LeBeau
712b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
7134f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
714923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
715923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
716025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
717025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
718025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
719f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (((mComposing.length() > 0 && mHasUncommittedTypedChars)
720b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                || mVoiceProxy.isVoiceInputHighlighted())
721025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                && (selectionChanged || candidatesCleared)) {
722025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            if (candidatesCleared) {
723025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // If the composing span has been cleared, save the typed word in the history for
724025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // recorrection before we reset the candidate strip.  Then, we'll be able to show
725025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // suggestions for recorrection right away.
726f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok                mRecorrection.saveRecorrectionSuggestion(mWord, mComposing);
727025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            }
728923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
729f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
73089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (isCursorTouchingWord()) {
731cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.cancelUpdateBigramPredictions();
73289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.postUpdateSuggestions();
73389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            } else {
73489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                setPunctuationSuggestions();
73589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
736923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
737923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
738923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
739923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
740923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
741b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.setVoiceInputHighlighted(false);
7424733609947c0ec74e460bd714fffca0518ade93aJean Chalard        } else if (!mHasUncommittedTypedChars && !mExpectingUpdateSelection) {
743662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka            if (TextEntryState.isAcceptedDefault() || TextEntryState.isSpaceAfterPicked()) {
744662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                if (TextEntryState.isAcceptedDefault())
745662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka                    TextEntryState.reset();
7469a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
747923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
7484733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (!mExpectingUpdateSelection) {
7494733609947c0ec74e460bd714fffca0518ade93aJean Chalard          mJustAddedMagicSpace = false; // The user moved the cursor.
7504733609947c0ec74e460bd714fffca0518ade93aJean Chalard          mJustReplacedDoubleSpace = false;
7514733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
7524733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mExpectingUpdateSelection = false;
753d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
754466741d8a78965b8509bf527344f289e50873092Mike LeBeau
755979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
756979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
757979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
758466741d8a78965b8509bf527344f289e50873092Mike LeBeau
7597a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.updateRecorrectionSelection(mKeyboardSwitcher,
7607a8dac55278cedd838be325f56b4c52d973c61f5satok                mCandidateView, candidatesStart, candidatesEnd, newSelStart,
7617a8dac55278cedd838be325f56b4c52d973c61f5satok                newSelEnd, oldSelStart, mLastSelectionStart,
7627a8dac55278cedd838be325f56b4c52d973c61f5satok                mLastSelectionEnd, mHasUncommittedTypedChars);
7637a8dac55278cedd838be325f56b4c52d973c61f5satok    }
7647a8dac55278cedd838be325f56b4c52d973c61f5satok
7657a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setLastSelection(int start, int end) {
7667a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionStart = start;
7677a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionEnd = end;
768923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
769923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
770c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
771c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
772c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
773c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
774c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
775c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
776c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
777c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
778c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
779c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
7807a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
781c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
782c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
783c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
784c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
785c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
786c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
787c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
788c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
789c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
790c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
791c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
792c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
793c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
794c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
795c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
7967a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
797c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
798c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
799c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
800c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
803979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
8041b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
805979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
8076e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8086e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8096e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8106e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
811b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
8129fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.clearWordsInHistory();
813923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
814923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
815923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8171b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
818979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
819a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
820bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
821bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
822bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
823bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
824923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8261b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8271b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8281b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
829b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
831923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
832a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8337e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8341b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8357e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
837979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
8387e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
840c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            setSuggestionStripShown(true);
841923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
842923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
844c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) {
8457a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        // TODO: Modify this if we support candidates with hard keyboard
8467e9615f218630d14ae5666ede2efd5f12d0a23c3Tadashi G. Takaoka        if (onEvaluateInputViewShown() && mCandidateViewContainer != null) {
8477a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final boolean shouldShowCandidates = shown
8487a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
8497a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (isExtractViewShown()) {
8507a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // No need to have extra space to show the key preview.
8517a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setMinimumHeight(0);
852c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
853c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.GONE);
8547a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            } else {
8557a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // We must control the visibility of the suggestion strip in order to avoid clipped
8567a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // key previews, even when we don't show the suggestion strip.
8577a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
8587a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.INVISIBLE);
8597a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            }
860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
862a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
863c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private void setSuggestionStripShown(boolean shown) {
864c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
865543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
866543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
867543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
870c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
8712951aa7e93c36fbbaff48139f3ff0ff6b67d05b7Tadashi G. Takaoka        if (inputView == null || mCandidateViewContainer == null)
87246ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
87346ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        final int containerHeight = mCandidateViewContainer.getHeight();
87446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        int touchY = containerHeight;
8759e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
87646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (mKeyboardSwitcher.isInputViewShown()) {
8777a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (mCandidateViewContainer.getVisibility() == View.VISIBLE) {
8787a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                touchY -= mCandidateStripHeight;
8799e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8807a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchWidth = inputView.getWidth();
8817a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchHeight = inputView.getHeight() + containerHeight
8827a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
8837a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
8849e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
8857a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
8867a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        + " height=" + touchHeight);
8879e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8887a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
8899e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
89046ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.contentTopInsets = touchY;
89146ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.visibleTopInsets = touchY;
892923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
893a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
894923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
895979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
896458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
897458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
898979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
900458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
901979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
902979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
903979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
904979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
905979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
906979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
907979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
908979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
911e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
912c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getKeyboardView() != null) {
913c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                if (mKeyboardSwitcher.getKeyboardView().handleBack()) {
9146e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
9156e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
916e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
917e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
918923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
919923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
925e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
926e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
927e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
928e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
929e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
930e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
931e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
932e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
933e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
934e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
935e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
936e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
937e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
938e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
939e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
940e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
941e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
943923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
946409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
947f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
948f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
955bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
961b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9631c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
96417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCap && ic != null && ei != null
96517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && ei.inputType != InputType.TYPE_NULL) {
966b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9671c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
968b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9691c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9701c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
971863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void swapSwapperAndSpace() {
972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
975863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
977863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                && lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
982b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9834ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
9844ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
9854ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
986863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void maybeDoubleSpace() {
987923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
993571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
994fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE
995fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && mHandler.isAcceptingDoubleSpaces()) {
996fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.cancelDoubleSpacesTimer();
997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
998923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1000923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1001b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10024733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mJustReplacedDoubleSpace = true;
1003fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        } else {
1004fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.startDoubleSpacesTimer();
1005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1007a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
100841a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
100941a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
101041a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
101141a519729505a877844f2c57a33509c302dddbceKen Wakasa
101241a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
101341a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
101441a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10154ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1016571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1017571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
101841a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
101941a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
102041a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
102141a519729505a877844f2c57a33509c302dddbceKen Wakasa
10229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
10239a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
10249a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
10259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
10269a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10279a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1028571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
10299a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
10309a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
10319a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
10329a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1033c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
1034923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1035923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
10366558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
10376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1038d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1039923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1044923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1045923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1047923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1048923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1049a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1050e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
1051d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        if (isShowingOptionDialog())
1052d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            return;
1053d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
1054d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            showSubtypeSelectorAndSettings();
1055d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
1056d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            showOptionsMenu();
1057d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        } else {
1058d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            launchSettings();
10599a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10609a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10619a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1062e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10639a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10649502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
106579efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10669a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10679a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10689a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10699a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10709a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10719a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10729a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
10739a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
10749a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10759a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10765f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
10775a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
10788aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1079923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1080571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1081923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1082923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1083923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1084b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1085b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
10864733609947c0ec74e460bd714fffca0518ade93aJean Chalard        final boolean lastStateOfJustReplacedDoubleSpace = mJustReplacedDoubleSpace;
10874733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mJustReplacedDoubleSpace = false;
1088923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1089571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
10904733609947c0ec74e460bd714fffca0518ade93aJean Chalard            handleBackspace(lastStateOfJustReplacedDoubleSpace);
10914189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
10924733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
10934189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
10944189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1095571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
10964189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1097101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1098b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
10994189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1100e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
11014189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1102101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1103b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
11044189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1105571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
11064189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
11074189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
11084189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11094189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1110e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1111e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
11124189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1113e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1114e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
11154189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1116d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_NEXT_LANGUAGE:
111788fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(true);
11184189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1119d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case LatinKeyboard.CODE_PREV_LANGUAGE:
112088fc9d44186120f9edc5cf7ec0e2af85260fed04satok            toggleLanguage(false);
11214189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1122571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1123b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
11244189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1125d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case Keyboard.CODE_SHORTCUT:
112620cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
11274189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1128571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
112945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
11304733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // There are two cases for tab. Either we send a "next" event, that may change the
11314733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // focus but will never move the cursor. Or, we send a real tab keycode, which some
11324733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // applications may accept or ignore, and we don't know whether this will move the
11334733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // cursor or not. So actually, we don't really know.
11344733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // So to go with the safer option, we'd rather behave as if the user moved the
11354733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // cursor when they didn't than the opposite. We also expect that most applications
11364733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // will actually use tab only for focus movement.
11374733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // To sum it up: do not update mExpectingUpdateSelection here.
11384189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
11394189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
114017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isWordSeparator(primaryCode)) {
1141b5d17e52fcda39d540822e615bfb7ed5074e0034satok                handleSeparator(primaryCode, x, y);
11424189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
11438fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                handleCharacter(primaryCode, keyCodes, x, y);
11444189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11454733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
11464733609947c0ec74e460bd714fffca0518ade93aJean Chalard            break;
1147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1148b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1149dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1150dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1152a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11535a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11548aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1155b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.commitVoiceInput();
1156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
11589fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.abortRecorrection(false);
1159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
116055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
116141a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1164b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11655f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
11660730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
1167dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11705a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11718aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
117283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11735f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
117483e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
117583e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
11764733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private void handleBackspace(boolean justReplacedDoubleSpace) {
1177b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.logAndRevertVoiceInput()) return;
11784f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1179504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1180504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1181979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1182979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1183b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleBackspace();
11844f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1185504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
1186f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1191923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
1193f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                    mHasUncommittedTypedChars = false;
1194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
119589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                if (1 == length) {
119689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // 1 == length means we are about to erase the last character of the word,
119789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // so we can show bigrams.
1198cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                    mHandler.postUpdateBigramPredictions();
119989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                } else {
120089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // length > 1, so we still have letters to deduce a suggestion from.
120189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    mHandler.postUpdateSuggestions();
120289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                }
1203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1209d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1210504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1212662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isUndoCommit()) {
1213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1214979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1216504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
12174733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (justReplacedDoubleSpace) {
12184733609947c0ec74e460bd714fffca0518ade93aJean Chalard            if (revertDoubleSpace()) {
12194733609947c0ec74e460bd714fffca0518ade93aJean Chalard              ic.endBatchEdit();
12204733609947c0ec74e460bd714fffca0518ade93aJean Chalard              return;
12214733609947c0ec74e460bd714fffca0518ade93aJean Chalard            }
12224733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
1223504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1224504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1225dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
12276558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
12286558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
122955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
12306558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
12316558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
12326558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
12336558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
12346558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
12356558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
12366558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
12396558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12406558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1243979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
124645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
124745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
1248b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
1249b2707856aba4fc9b063f26305f1fb603b19c1701satok                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
125045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
125145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
125245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
125345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
125445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
125545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
125645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
125745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
125845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
125945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
1260b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
126145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
1262b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionNext(ic);
1263b2707856aba4fc9b063f26305f1fb603b19c1701satok        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
126445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
1265b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionPrevious(ic);
126645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
126745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
126845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
12698fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
1270b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleCharacter();
12714f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
127217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceStripper(primaryCode)) {
12730730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            removeTrailingSpace();
12740730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        }
12750730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard
1276863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mLastSelectionStart == mLastSelectionEnd) {
12779fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1278b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12794f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1280e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
12819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
1282f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            if (!mHasUncommittedTypedChars) {
1283f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
1284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1285f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok                mRecorrection.saveRecorrectionSuggestion(mWord, mBestWord);
1286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
12877e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1288923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
129035f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
1291f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1292eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1293eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1294eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1295eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1296e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1297e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
129835f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                // In some locales, such as Turkish, Character.toUpperCase() may return a wrong
129935f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                // character because it doesn't take care of locale.
130035f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                final String upperCaseString = new String(new int[] {code}, 0, 1)
130135f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                        .toUpperCase(mSubtypeSwitcher.getInputLocale());
130235f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) {
130335f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                    code = upperCaseString.codePointAt(0);
130412a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
130512a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
130635f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                    onTextInput(upperCaseString);
130712a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
130812a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1309979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1311f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1312f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1313f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
13140b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1316e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
13178fbd55229243cb66c03d5ea1f79dfb39f596590dsatok            mWord.add(code, keyCodes, x, y);
1318923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
13201c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
13211c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1322b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
13231c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1326d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1328e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
133017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1331863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            swapSwapperAndSpace();
1332863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        } else {
1333863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            mJustAddedMagicSpace = false;
1334863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1335863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1336b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1337979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
133817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y);
1339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1341b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private void handleSeparator(int primaryCode, int x, int y) {
1342b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleSeparator();
13434f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
134455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
13456558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1346cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1347d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
13486558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
13496558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1350923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1351923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
13521b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1354923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
13559fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1356923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1357f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1359a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1361923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
136217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            final boolean shouldAutoCorrect =
136317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    (mSettingsValues.mAutoCorrectEnabled || mSettingsValues.mQuickFixes)
136417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && !mInputTypeNoAutoCorrect && mHasDictionary;
136517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
1366b5d17e52fcda39d540822e615bfb7ed5074e0034satok                pickedDefault = pickDefaultSuggestion(primaryCode);
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13714ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1372863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mJustAddedMagicSpace) {
137317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1374863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1375863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                swapSwapperAndSpace();
1376863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            } else {
137717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (mSettingsValues.isMagicSpaceStripper(primaryCode)) removeTrailingSpace();
1378863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1379863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                mJustAddedMagicSpace = false;
1380863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            }
13810730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        } else {
13820730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendKeyChar((char)primaryCode);
13834ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13844ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1385863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1386863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            maybeDoubleSpace();
1387863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1388863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1389b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) primaryCode, true, x, y);
139089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1391979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
139255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
139355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
139455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
1395b2707856aba4fc9b063f26305f1fb603b19c1701satok                InputConnectionCompatUtils.commitCorrection(
139689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
139755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
139855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
139955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
140089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
140189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (Keyboard.CODE_SPACE == primaryCode) {
140289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isCursorTouchingWord()) {
140389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateSuggestions();
140489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateOldSuggestions();
1405cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.postUpdateBigramPredictions();
140689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
140789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
140889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Set punctuation right away. onUpdateSelection will fire but tests whether it is
140989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // already displayed or not, so it's okay.
141055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1412b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1417466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1420b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleClose();
1421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
1422c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
14231679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
14241679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1426923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14277a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isSuggestionsRequested() {
1428c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1429c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1431a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
14327a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingPunctuationList() {
143317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSuggestPuncList == mCandidateView.getSuggestions();
14347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14367a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingSuggestionsStrip() {
14377599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
14387599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
14397599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
14407599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14417599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14429fbfd5877305ed19a20663630b498b6b3fdae942satok    public boolean isCandidateStripVisible() {
1443b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1444b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1445952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
14469fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
14489fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
14499fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
14509fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14519fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1453923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1454409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1455060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1456060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1457060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1458c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        View v = mKeyboardSwitcher.getKeyboardView();
1459060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1460060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1461060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1462060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1463060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
14645a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1465060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1466060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1467c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShown(isCandidateStripVisible());
1468060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1469060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1470466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1471466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1472409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14737e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1474466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1475466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14767e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1477466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
14787e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
14795e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka            mKeyboardSwitcher.onAutoCorrectionStateChanged(
14805e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka                    words.hasWordAboveAutoCorrectionScoreThreshold());
1481466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1482466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1483466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1484409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
14869fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1487b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                && !mVoiceProxy.isVoiceInputHighlighted()) {
1488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1490466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1491f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
1492ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1494923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1495979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1496979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1497979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1498979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
14999f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: May need a better way of retrieving previous word
1500e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
150117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
15027e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
1503c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                mKeyboardSwitcher.getKeyboardView(), word, prevWord);
1504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
15056f99d12b0752ecdbceda7e5fddead214f939f533Tadashi G. Takaoka        boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
1506a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1507bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Here, we want to promote a whitelisted word if exists.
1508bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
1509bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
1510979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1511979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15144a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1515979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1516952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        correctionAvailable &= !TextEntryState.isRecorrecting();
1517979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1518a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1519a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1520f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1521f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1522f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1523f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1524fe1a6d961cf039357f061482461e4d2e951ad346satok        if (typedWord != null) {
1525fe1a6d961cf039357f061482461e4d2e951ad346satok            if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1526fe1a6d961cf039357f061482461e4d2e951ad346satok                    || mCandidateView.isShowingAddToDictionaryHint()) {
1527fe1a6d961cf039357f061482461e4d2e951ad346satok                builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(
1528fe1a6d961cf039357f061482461e4d2e951ad346satok                        correctionAvailable);
1529fe1a6d961cf039357f061482461e4d2e951ad346satok            } else {
1530fe1a6d961cf039357f061482461e4d2e951ad346satok                final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
1531fe1a6d961cf039357f061482461e4d2e951ad346satok                if (previousSuggestions == mSettingsValues.mSuggestPuncList)
1532fe1a6d961cf039357f061482461e4d2e951ad346satok                    return;
1533fe1a6d961cf039357f061482461e4d2e951ad346satok                builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
1534fe1a6d961cf039357f061482461e4d2e951ad346satok            }
15359fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
15367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1537979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
15384a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
15399fbfd5877305ed19a20663630b498b6b3fdae942satok    public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
15407e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
15417e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
154214e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
154382411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
154482411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
15457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1546923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1547923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1549923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1552c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShown(isCandidateStripVisible());
1553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1555b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private boolean pickDefaultSuggestion(int separatorCode) {
1556923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1557d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1558d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15616780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1562b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord, separatorCode);
15634733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
15641fef530ec7626fa16777f52b48191e61db8f46d4satok            commitBestWord(mBestWord);
15659468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1566bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1567979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1568923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1569979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1570923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1571923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1572c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
1573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
15747e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
157517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
157617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
15774f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1578952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        final boolean recorrecting = TextEntryState.isRecorrecting();
15799a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
15809a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
15819a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
15829a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
15831b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
15841b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
15851b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1586923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1587923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1588923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1589923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1590923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1591923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1592923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1593b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
15949a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15959a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
15969a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1597923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15996a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
16006a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
160117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0))
160217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) {
1603979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1604979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1605979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
16067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
1607863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // Find out whether the previous character is a space. If it is, as a special case
1608863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // for punctuation entered through the suggestion strip, it should be considered
1609863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a magic space even if it was a normal space. This is meant to help in case the user
1610863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // pressed space on purpose of displaying the suggestion strip punctuation.
161155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1612eaa10f44a4a0108a90803b1b28238842d3fb5addsatok            final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : "";
16131f050f634820a1d980e8a91f3a962bcd1fc242e3satok            final int toLeft = (ic == null || TextUtils.isEmpty(beforeText))
16141f050f634820a1d980e8a91f3a962bcd1fc242e3satok                    ? 0 : beforeText.charAt(0);
16154f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            final boolean oldMagicSpace = mJustAddedMagicSpace;
1616863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true;
1617a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1618a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1619a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
16204f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            mJustAddedMagicSpace = oldMagicSpace;
16219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16239a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
16246a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
16256a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
1626f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
162789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // If we are not composing a word, then it was a suggestion inferred from
162889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // context - no user input. We should reset the word composer.
162989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            mWord.reset();
163089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
16314733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mExpectingUpdateSelection = true;
16321fef530ec7626fa16777f52b48191e61db8f46d4satok        commitBestWord(suggestion);
16339468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
16340c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1635bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1636979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1637bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToOnlyBigramDictionary(suggestion, 1);
16380c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1639979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
16407e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1641923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1642923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
16430730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        if (mShouldInsertMagicSpace && !recorrecting) {
16440730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendMagicSpace();
1645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1646979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
16477f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We should show the hint if the user pressed the first entry AND either:
16487f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
16497f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        //   AND mHasDictionary is false)
16507f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
16517f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
16527f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
16537f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
16547f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
1655bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
1656bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                // If there is no dictionary the hint should be shown.
1657bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                && (!mHasDictionary
1658bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        // If "suggestion" is not in the dictionary, the hint should be shown.
1659bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        || !AutoCorrection.isValidWord(
1660bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                                mSuggest.getUnigramDictionaries(), suggestion, true));
1661b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1662952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!recorrecting) {
1663b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1664b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1665b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1666b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
1667b5d17e52fcda39d540822e615bfb7ed5074e0034satok                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1668777118a40a363ccab69a00016d3156066513cb78Jean Chalard        }
1669777118a40a363ccab69a00016d3156066513cb78Jean Chalard        if (!showingAddToDictionaryHint) {
1670364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1671979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
167241ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            updateBigramPredictions();
167341ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // Updating the predictions right away may be slow and feel unresponsive on slower
167441ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // terminals. On the other hand if we just postUpdateBigramPredictions() it will
167541ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // take a noticeable delay to update them which may feel uneasy.
1676979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1677b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
167866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
167966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16809a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16819a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16829a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1683923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1684a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1685979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1686979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1687979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1688979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
16891fef530ec7626fa16777f52b48191e61db8f46d4satok    private void commitBestWord(CharSequence bestWord) {
1690b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1691b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
16921679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1694923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
16951fef530ec7626fa16777f52b48191e61db8f46d4satok            mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators);
16961fef530ec7626fa16777f52b48191e61db8f46d4satok            SuggestedWords suggestedWords = mCandidateView.getSuggestions();
16971fef530ec7626fa16777f52b48191e61db8f46d4satok            ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
16981fef530ec7626fa16777f52b48191e61db8f46d4satok                    this, bestWord, suggestedWords), 1);
1699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
17001fef530ec7626fa16777f52b48191e61db8f46d4satok        mRecorrection.saveRecorrectionSuggestion(mWord, bestWord);
1701f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
17021fef530ec7626fa16777f52b48191e61db8f46d4satok        mCommittedLength = bestWord.length();
1703923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
170589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    private static final WordComposer sEmptyWordComposer = new WordComposer();
170641ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard    public void updateBigramPredictions() {
170789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (mSuggest == null || !isSuggestionsRequested())
170889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            return;
170989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
171017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mBigramPredictionEnabled) {
1711cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            setPunctuationSuggestions();
1712cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            return;
1713cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        }
1714cb3320179d39a7983874697a0aa428b127675c9dJean Chalard
171589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
171617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
171789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
1718c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                mKeyboardSwitcher.getKeyboardView(), sEmptyWordComposer, prevWord);
171989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
172089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (builder.size() > 0) {
172189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Explicitly supply an empty typed word (the no-second-arg version of
172289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // showSuggestions will retrieve the word near the cursor, we don't want that here)
172389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            showSuggestions(builder.build(), "");
172489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
172589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isShowingPunctuationList()) setPunctuationSuggestions();
172689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
172789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    }
172889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
17297a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setPunctuationSuggestions() {
173017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        setSuggestions(mSettingsValues.mSuggestPuncList);
1731c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShown(isCandidateStripVisible());
17326a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
17336a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1734bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) {
1735979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1736979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1737979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1738bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1739979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1740979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1741979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1742979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1743979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1744bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
1745979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1746979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1747bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            boolean selectedANotTypedWord) {
1748979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
1749bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
17500c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
17510c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
17520c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1753979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1754979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1755979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1756979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1757bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
1758bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean selectedATypedWordAndItsInAutoDic =
1759bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                !selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion);
1760bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean isValidWord = AutoCorrection.isValidWord(
1761bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), suggestion, true);
1762bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic
1763bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                || !isValidWord;
1764bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        if (needsToAddToAutoDictionary) {
1765e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1766e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1767979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1768e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1769863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // We don't want to register as bigrams words separated by a separator.
1770863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // For example "I will, and you too" : we don't want the pair ("will" "and") to be
1771863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a bigram.
1772e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
177317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    mSettingsValues.mWordSeparators);
1774e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1775e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1776979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
177732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
177832e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
177932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
17807a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isCursorTouchingWord() {
1781923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1782923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1783923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1784923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1785923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
178617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toLeft.charAt(0))
178717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) {
1788923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1789923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1790a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
179117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toRight.charAt(0))
179217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) {
1793923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1794923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1795923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1796923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1797a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1798dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1799dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1800dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1801dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1802dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
1805f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars && length > 0) {
1806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1807504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1808923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1810504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
181117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (!TextUtils.isEmpty(toTheLeft)
181217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && mSettingsValues.isWordSeparator(toTheLeft.charAt(0))) {
1813923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1814923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1815923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
181630be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
181730be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
181830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
181917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && !TextUtils.isEmpty(punctuation)
182017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                    && mSettingsValues.isWordSeparator(punctuation.charAt(0))
182130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1822504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1823504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
182430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
1825b5d17e52fcda39d540822e615bfb7ed5074e0034satok                TextEntryState.typedCharacter(punctuation.charAt(0), true,
1826b5d17e52fcda39d540822e615bfb7ed5074e0034satok                        WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
182730be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
182830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1829504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
1830f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
1831504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1832504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1833504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1834cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1835d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1838923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18414733609947c0ec74e460bd714fffca0518ade93aJean Chalard    public boolean revertDoubleSpace() {
18424733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mHandler.cancelDoubleSpacesTimer();
18434733609947c0ec74e460bd714fffca0518ade93aJean Chalard        final InputConnection ic = getCurrentInputConnection();
18444733609947c0ec74e460bd714fffca0518ade93aJean Chalard        // Here we test whether we indeed have a period and a space before us. This should not
18454733609947c0ec74e460bd714fffca0518ade93aJean Chalard        // be needed, but it's there just in case something went wrong.
18464733609947c0ec74e460bd714fffca0518ade93aJean Chalard        final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
18474733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (!". ".equals(textBeforeCursor))
18484733609947c0ec74e460bd714fffca0518ade93aJean Chalard            return false;
18494733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.beginBatchEdit();
18504733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.deleteSurroundingText(2, 0);
18514733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.commitText("  ", 1);
18524733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.endBatchEdit();
18534733609947c0ec74e460bd714fffca0518ade93aJean Chalard        return true;
18544733609947c0ec74e460bd714fffca0518ade93aJean Chalard    }
18554733609947c0ec74e460bd714fffca0518ade93aJean Chalard
1856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
185717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.isWordSeparator(code);
1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18600730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private void sendMagicSpace() {
1861571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
18620730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = true;
1863b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1865923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
18670b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
187088fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
1871c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1872c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
18734ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1874cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(),
1875b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mSubtypeSwitcher.isShortcutImeEnabled() && mVoiceProxy.isVoiceButtonEnabled(),
1876b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                mVoiceProxy.isVoiceButtonOnPrimary());
18770ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
187817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
18794b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
188036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
188136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
188288fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
188388fc9d44186120f9edc5cf7ec0e2af85260fed04satok    private void toggleLanguage(boolean next) {
188488fc9d44186120f9edc5cf7ec0e2af85260fed04satok        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
188588fc9d44186120f9edc5cf7ec0e2af85260fed04satok            mSubtypeSwitcher.toggleLanguage(next);
188688fc9d44186120f9edc5cf7ec0e2af85260fed04satok        }
188717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // The following is necessary because on API levels < 10, we don't get notified when
188817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // subtype changes.
18895a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED)
18905a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            onRefreshKeyboard();
189117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard     }
189288fc9d44186120f9edc5cf7ec0e2af85260fed04satok
18935a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
18948aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
189517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mSwipeDownDismissKeyboardEnabled)
1896363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1897923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
18995a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1900e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPress(int primaryCode, boolean withSliding) {
1901cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1902cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1903cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1904cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
19051679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19061679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1907571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1908e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onPressShift(withSliding);
1909e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19106c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
191140a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
19126c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1913681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19165a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1917e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onRelease(int primaryCode, boolean withSliding) {
19181679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19193f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
19201679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1921571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1922e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onReleaseShift(withSliding);
1923e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19246c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
192540a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1926923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1927a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1928a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1929123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
1930923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1931923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1932923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1933123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
1934123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
1935123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
1936123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1937123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
1938123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
1939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
1943923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
1944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1946923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
194817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
1949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
1953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
1954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
1955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1956c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            if (mKeyboardSwitcher.getKeyboardView() != null) {
1957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
1958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
196017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (isSoundOn()) {
1961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
1962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
1963923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
1964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
1965571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
1966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
1967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1968571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
1969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
1970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1971571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
1972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
1973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1975923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
1976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1979409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
198017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mVibrateOn) {
1981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1983c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
19841679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
19851679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
1986979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
198766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
1988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
199171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
19926516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
19936516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
19946516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
199517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    boolean isSoundOn() {
199617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSoundOn && !mSilentModeOn;
1997979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1998979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1999e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
20009f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: cleanup messy flags
2001e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
200217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        final boolean shouldAutoCorrect = (mSettingsValues.mAutoCorrectEnabled
200317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                || mSettingsValues.mQuickFixes) && !mInputTypeNoAutoCorrect && mHasDictionary;
200417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled)
2005e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
200617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
200717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect
200817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && mSettingsValues.mAutoCorrectEnabled)
2009979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2010e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2011e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2012e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2013e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2014e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
20150ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
201632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
201717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mSuggest.setQuickFixesEnabled(mSettingsValues.mQuickFixes
20184ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
201932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
202032e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
202117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) {
20227599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
20239502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2024458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
20257599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2026458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
20277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
20287599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
20297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
20307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
20317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
20327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2033466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
20349502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
2035466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2036466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2037bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
20389502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
2039bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2040bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2041507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
2042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2044466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2045923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2047923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2048923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
205085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
205185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
205285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
205385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
205485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
205585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
205685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
20572fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
20582fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
20592fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
20602fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
206185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
20622cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
20632cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
20642fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
20652fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
20662fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
20672fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2068aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2069aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2070aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
20712fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
20722fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
207385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
207485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
20752fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
207885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
207985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
208085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
208185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
208285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
208385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
20845a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2085923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2086923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2087923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
208885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2089ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
20902fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
209185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2092ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
20932fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2094923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2095923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
209685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
209785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
20982fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
20992fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
210085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
210185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
2102c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        final IBinder windowToken = mKeyboardSwitcher.getKeyboardView().getWindowToken();
210318e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        if (windowToken == null) return;
21042fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
21052fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
21062fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
21072fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
210885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
210985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2111a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
211418e15a1e5e30cf200e935e43a73edef25682de27Ken Wakasa        lp.token = windowToken;
2115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21217e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
21227e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2124a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
21299fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
2131f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        p.println("  mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
213217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
21330730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        p.println("  mShouldInsertMagicSpace=" + mShouldInsertMagicSpace);
21341b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
213617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mSoundOn=" + mSettingsValues.mSoundOn);
213717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mVibrateOn=" + mSettingsValues.mVibrateOn);
2138240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        p.println("  mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
2139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
21406e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2142a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2147a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2159