LatinIME.java revision 728115493e14f84d5f02a4812c8086a378813364
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
195a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
205a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
215a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId;
22571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
235a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
24de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
255a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
269502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaokaimport com.android.inputmethod.latin.Utils.RingCharBuffer;
27409220583333bdf06290dd9fd42f91b5c0d1b11asatokimport com.android.inputmethod.voice.VoiceIMEConnector;
28388ce92ab8a635c5ad44620dad59baf05dfea510Amith Yamasani
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
3736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
40123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
454174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasaimport android.os.Vibrator;
46bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
48e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
50979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
54e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.Gravity;
5566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
57e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.LayoutInflater;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
598e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
608e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
641b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaokaimport android.view.inputmethod.CorrectionInfo;
65923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
66466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
67466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedTextRequest;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputMethodManager;
700ed7191b4d1013a0b9d2fd1f26733dee7364871dsatokimport android.view.inputmethod.InputMethodSubtype;
719e347d3d448e48229c46aad394ec9bd60cd5807bsatokimport android.widget.FrameLayout;
72e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.HorizontalScrollView;
7340ac45ebdcd71940394dda00371d4847f7db0f26Ken Wakasaimport android.widget.LinearLayout;
74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
75466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
76466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
77466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.ArrayList;
78b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimodaimport java.util.Arrays;
79466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
80466741d8a78965b8509bf527344f289e50873092Mike LeBeau
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
8455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokapublic class LatinIME extends InputMethodService implements KeyboardActionListener,
85e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        SharedPreferences.OnSharedPreferenceChangeListener {
86466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String TAG = "LatinIME";
87979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
88409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
89910b73127fa207dd26ec8124000262523b0aac0csatok    private static boolean DEBUG = LatinImeLogger.sDBG;
90a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
91fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_SUGGESTIONS = 180;
92fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
93d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    private static final int DELAY_UPDATE_SHIFT_STATE = 300;
949e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
95fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
99d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
100a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1017599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1027599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1037599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1047599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1057599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1067599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1077599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1087599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1097599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1107599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1117599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1127599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1137599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1147599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
115e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1181b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
119a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
121a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12279efbed76f638be298493107fa2d0cd1b5eb529esatok    private InputMethodManager mImm;
1232fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1242fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1252fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
12671c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1270ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
128409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private VoiceIMEConnector mVoiceConnector;
129a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
131979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1322bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1334ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
13436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
135c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
136c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mAutoSpace;
137c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
138c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
139c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
140c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
14171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
1449fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean mHasValidSuggestions;
145e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1469a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private boolean mJustAddedAutoSpace;
147e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
14866b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok    private boolean mReCorrectionEnabled;
149979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mBigramSuggestionEnabled;
150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
153979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mPopupOn;
154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
1556e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
1562fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private boolean mConfigEnableShowSubtypeSettings;
157363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka    private boolean mConfigSwipeDownDismissKeyboardEnabled;
158de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
159de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDurationOfFadeoutLanguageOnSpacebar;
160d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka    private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
161409220583333bdf06290dd9fd42f91b5c0d1b11asatok
16279efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
16379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
16479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
165979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
16679efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
16779efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
1687e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestPuncList;
169979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
172c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa    private boolean mJustReverted;
173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
175a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
1772296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
17871c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
181979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /* package */ String mWordSeparators;
182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mSentenceSeparators;
183979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private String mSuggestPuncs;
184409220583333bdf06290dd9fd42f91b5c0d1b11asatok    // TODO: Move this flag to VoiceIMEConnector
18581c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
186466741d8a78965b8509bf527344f289e50873092Mike LeBeau
187dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
188dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
189979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mRefreshKeyboardRequired;
190dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
19171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
192979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
193979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public abstract static class WordAlternatives {
194979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        protected CharSequence mChosenWord;
1954f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
196979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives() {
197979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
198979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
199979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
200979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives(CharSequence chosenWord) {
201979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mChosenWord = chosenWord;
202979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
203979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
204979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
205979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public int hashCode() {
206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord.hashCode();
207979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
208979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
209979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public abstract CharSequence getOriginalWord();
210979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
211979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getChosenWord() {
212979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord;
213979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
214979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public abstract SuggestedWords.Builder getAlternatives();
216979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
217979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
218979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public class TypedWordAlternatives extends WordAlternatives {
219979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        private WordComposer word;
220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
221979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives() {
222979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
223979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
224979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
225979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
226979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            super(chosenWord);
227979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            word = wordComposer;
228979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
230979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
231979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getOriginalWord() {
232979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return word.getTypedWord();
233979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
234979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
235979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
2367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public SuggestedWords.Builder getAlternatives() {
237979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return getTypedSuggestions(word);
238979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
239979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
24036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
241571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
242d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
243409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
244d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
245d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
247d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
248de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
249de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
250d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
253de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
254de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
256d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
257d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
258d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
259d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
260d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                setOldSuggestions();
261d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
262d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
263de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
264d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
266e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mVoiceConnector.handleVoiceResults(preferCapitalization()
267de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
268de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
269de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
270de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
27166432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
272d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
27366432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
274de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
275de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        mConfigDurationOfFadeoutLanguageOnSpacebar);
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
277de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
278de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
27966432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
280d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), DELAY_UPDATE_SUGGESTIONS);
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
294d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
295d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
296d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
297d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
298d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
299d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
300d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                    DELAY_UPDATE_OLD_SUGGESTIONS);
302d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
304d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
306d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
309d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), DELAY_UPDATE_SHIFT_STATE);
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
320de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
321d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
322de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
323de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
324de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
325de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
326de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                final LatinKeyboard keyboard = inputView.getLatinKeyboard();
327de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
328de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
329d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
330d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
331de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is always displayed when the delay is negative.
332d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
333de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
334de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                            mConfigDelayBeforeFadeoutLanguageOnSpacebar);
335de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
336de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
337de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
338d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3407e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3417e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
34227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
34327d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
34427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
34527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
34627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
347363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
349363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
35079efbed76f638be298493107fa2d0cd1b5eb529esatok        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
3512fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getApplicationInfo().packageName);
3520ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3530ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
354363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
355363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
356363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
357fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
358fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // If the option should not be shown, do not read the recorrection preference
359fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // but always use the default setting defined in the resources.
360fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
361fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard            mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
362fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard                    res.getBoolean(R.bool.default_recorrection_enabled));
363fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        } else {
364fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard            mReCorrectionEnabled = res.getBoolean(R.bool.default_recorrection_enabled);
365fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        }
366fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
3672fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mConfigEnableShowSubtypeSettings = res.getBoolean(
3682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                R.bool.config_enable_show_subtype_settings);
369363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
370363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                R.bool.config_swipe_down_dismiss_keyboard_enabled);
371de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
372de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_delay_before_fadeout_language_on_spacebar);
373de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
374de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_duration_of_fadeout_language_on_spacebar);
375d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
37666432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
377979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3789502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
379979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
3809502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
381979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
3820ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
383979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
384979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
3859502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
386979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
387979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
388979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
389363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
3906a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
391b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
392123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        // register to receive ringer mode change and network state change.
393123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
394123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
395123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
396923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
39727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
3983f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        prefs.registerOnSharedPreferenceChangeListener(this);
399923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
40036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
401979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
402458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa     * Returns a main dictionary resource id
403458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa     * @return main dictionary resource id
404979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
405458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa    public static int getMainDictionaryResourceId(Resources res) {
406458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final String MAIN_DIC_NAME = "main";
407979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        String packageName = LatinIME.class.getPackage().getName();
408458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
409979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
410979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4110ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
4120ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
4134ab730dbd34fad323063f2ffd31ce33de746668dsatok        String locale = mSubtypeSwitcher.getInputLocaleStr();
41436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4150ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
41636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
41736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
41836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
41927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
42089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
421979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
422458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
423458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        int mainDicResId = getMainDictionaryResourceId(res);
424458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSuggest = new Suggest(this, mainDicResId);
4251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
426e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
4270ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mUserDictionary = new UserDictionary(this, locale);
428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
429e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
430e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4312bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
432e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
433e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
43434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
435e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
436e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
437e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
438e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
439e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
440458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mWordSeparators = res.getString(R.string.word_separators);
441458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSentenceSeparators = res.getString(R.string.sentence_separators);
44236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4430ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.changeSystemLocale(savedLocale);
444923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
44536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
446466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
447466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
448e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
449e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
450e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
451979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
453409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.destroy();
454979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
455979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
456923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
461dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
462b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
463b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
464466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
465466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
466466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
467b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
4682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
4692fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
470b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
4718b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
47281c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
474bbd651a00898dabf6b2ae0e715d99953ea81063fLuca Zanolin        mVoiceConnector.onConfigurationChanged(conf);
47581c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
477b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
478923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
479923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
4808d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
485e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
486e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
487e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
488e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (container.getPaddingRight() != 0) {
489e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            HorizontalScrollView scrollView =
490e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                    (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view);
491e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
492e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            container.setGravity(Gravity.CENTER_HORIZONTAL);
493e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
494e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
497e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
498923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
50047f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    private static boolean isPasswordVariation(int variation) {
501e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
502e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
503e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
50447f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    }
50547f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins
50647f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    private static boolean isEmailVariation(int variation) {
507e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
508e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
50947f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    }
51047f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins
511a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
51345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
51445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5158e09172df1bb176cc899940862c56bed9b9aec4esatok
516910b73127fa207dd26ec8124000262523b0aac0csatok        if(DEBUG) {
517910b73127fa207dd26ec8124000262523b0aac0csatok            Log.d(TAG, "onStartInputView: " + inputView);
518910b73127fa207dd26ec8124000262523b0aac0csatok        }
519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
520979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5248d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5254ab730dbd34fad323063f2ffd31ce33de746668dsatok
52636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mRefreshKeyboardRequired) {
52736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = false;
528c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            onRefreshKeyboard();
52936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
53036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.newSession(this);
5326c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
533c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
534c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
535c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
536c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.resetVoiceStates(isPasswordVariation(
537c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                attribute.inputType & InputType.TYPE_MASK_VARIATION));
538c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
539c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
540c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
541c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
542c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
543c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
544c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHasValidSuggestions = false;
545c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
546c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mJustAddedAutoSpace = false;
547c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
548c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        loadSettings(attribute);
549c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
550c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.loadKeyboard(mode, attribute.imeOptions,
551c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonEnabled(),
552c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonOnPrimary());
553c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
554c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
555c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
556c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(),
557c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                false /* needsInputViewShown */ );
558c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
559c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
560c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
561c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
562c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
563c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setPreviewEnabled(mPopupOn);
564c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
565c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
566c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        checkReCorrectionOnStart();
567c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
568c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
569c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.onStartInputView(inputView.getWindowToken());
570c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
571c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
572c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
573c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
574c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private int initializeInputAttributesAndGetMode(int inputType) {
575c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
576c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mAutoSpace = false;
577e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
5789fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
5791b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
5801b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
581dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
582f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka        final int mode;
583c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        switch (inputType & InputType.TYPE_MASK_CLASS) {
584e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_NUMBER:
585e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_DATETIME:
5865a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_NUMBER;
5872c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                break;
588e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_PHONE:
5895a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_PHONE;
590923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
591e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_TEXT:
5929fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = true;
593923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Make sure that passwords are not displayed in candidate view
59447f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isPasswordVariation(variation)) {
5959fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
596923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
59747f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isEmailVariation(variation)
598e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = false;
600923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
601923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = true;
602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
60347f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isEmailVariation(variation)) {
6049fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6055a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_EMAIL;
606e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
6079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6085a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_URL;
609e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
6105a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_IM;
611e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
6129fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6135a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_TEXT;
614e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
6155a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_WEB;
6166c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // If it's a browser edit field and auto correct is not ON explicitly, then
6176c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // disable auto correction, but keep suggestions on.
618c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
619e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                        mInputTypeNoAutoCorrect = true;
6206c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    }
621f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka                } else {
6225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_TEXT;
623923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
62436ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani
62536ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If NO_SUGGESTIONS is set, don't do prediction.
626c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
6279fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
628e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
62936ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
63036ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If it's not multiline and the autoCorrect flag is not set, then don't correct
631c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
632c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                        (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
633e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
63436ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
635c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
6369fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6371b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    mApplicationSpecifiedCompletionOn = isFullscreenMode();
638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
639923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
640923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            default:
6415a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_TEXT;
642f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka                break;
643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
644c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mode;
645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
646923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
647b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    private void checkReCorrectionOnStart() {
648d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (!mReCorrectionEnabled) return;
649d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
650d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
651d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (ic == null) return;
652d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        // There could be a pending composing span.  Clean it up first.
653d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        ic.finishComposingText();
654d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
6559fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isShowingSuggestionsStrip() && isSuggestionsRequested()) {
656b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // First get the cursor position. This is required by setOldSuggestions(), so that
657b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // it can pass the correct range to setComposingRegion(). At this point, we don't
6584ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka            // have valid values for mLastSelectionStart/End because onUpdateSelection() has
659b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // not been called yet.
660b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedTextRequest etr = new ExtractedTextRequest();
661b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            etr.token = 0; // anything is fine here
662b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedText et = ic.getExtractedText(etr, 0);
663b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            if (et == null) return;
664b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
665b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionStart = et.startOffset + et.selectionStart;
666b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionEnd = et.startOffset + et.selectionEnd;
667b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
668b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // Then look for possible corrections in a delayed fashion
66955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) {
670d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateOldSuggestions();
67155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            }
672b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani        }
673b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    }
674b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
675923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
678a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
679979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6801b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
681979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
682409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
683409220583333bdf06290dd9fd42f91b5c0d1b11asatok
6845a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
685d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6864ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
687979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
688466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
689466741d8a78965b8509bf527344f289e50873092Mike LeBeau
690466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
6916495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
6926495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
6935a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
694d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
695d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
696d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
697d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
6986495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
6996495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
7006495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
701466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
702466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
703409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.showPunctuationHintIfNecessary();
704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
705923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
712466741d8a78965b8509bf527344f289e50873092Mike LeBeau
713466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
714466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
715466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
716466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
717466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
718466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
719466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
720466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
721466741d8a78965b8509bf527344f289e50873092Mike LeBeau
722409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setCursorAndSelection(newSelEnd, newSelStart);
7234f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
725923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
7269fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((((mComposing.length() > 0 && mHasValidSuggestions)
7278e09172df1bb176cc899940862c56bed9b9aec4esatok                || mVoiceConnector.isVoiceInputHighlighted()) && (newSelStart != candidatesEnd
7288e09172df1bb176cc899940862c56bed9b9aec4esatok                        || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart)) {
729923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
7309fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
731d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
732923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
736923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
737409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.setVoiceInputHighlighted(false);
7389fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (!mHasValidSuggestions && !mJustAccepted) {
7399a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            switch (TextEntryState.getState()) {
740e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case ACCEPTED_DEFAULT:
741e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                TextEntryState.reset();
742e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                // $FALL-THROUGH$
743e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case SPACE_AFTER_PICKED:
744e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mJustAddedAutoSpace = false; // The user moved the cursor.
745e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
746e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            default:
747e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
7489a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
749923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
750923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
751d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
752466741d8a78965b8509bf527344f289e50873092Mike LeBeau
753979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
754979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
755979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
756466741d8a78965b8509bf527344f289e50873092Mike LeBeau
7579fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isShowingSuggestionsStrip()) {
75866b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok            // Don't look for corrections if the keyboard is not visible
7591679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()) {
76066b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                // Check if we should go in or out of correction mode.
7619fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                if (isSuggestionsRequested() && !mJustReverted
76266b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
76366b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                                || TextEntryState.isCorrecting())
7649fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                                && (newSelStart < newSelEnd - 1 || !mHasValidSuggestions)) {
76566b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
766d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                        mHandler.postUpdateOldSuggestions();
76766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    } else {
76866b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        abortCorrection(false);
76955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        // Show the punctuation suggestions list if the current one is not
770364da8c618303a7764595d2c15ee034a7671365dKen Wakasa                        // and if not showing "Touch again to save".
7717599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        if (mCandidateView != null && !isShowingPunctuationList()
7727599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                                && !mCandidateView.isShowingAddToDictionaryHint()) {
773ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                            setPunctuationSuggestions();
77455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        }
77566b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    }
776b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
777466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
778466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
780923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
781c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
782c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
783c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
784c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
785c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
786c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
787c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
788c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
789c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
790c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
7919fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
792c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
793c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
794c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
795c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
796c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
797c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
798c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
799c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
800c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
801c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
802c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
803c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
804c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
805c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
806c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
8079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
808c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
809c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
810c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
811c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
812923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
813923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
814979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
8151b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
816979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
8186e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8196e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8206e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8216e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
822409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.hideVoiceWindow(mConfigurationChanging);
823979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.clear();
824923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
826923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
827923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
828923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8291b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
830979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
831a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
8321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int count = (applicationSpecifiedCompletions != null)
8331b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    ? applicationSpecifiedCompletions.length : 0;
8341b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            for (int i = 0; i < count; i++) {
835a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8381b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8391b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8401b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
841b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
842923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
844a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8461b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8477e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8487e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
849979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
8507e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
852543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
856543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // TODO: Remove this if we support candidates with hard keyboard
858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
8591679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            super.setCandidatesViewShown(shown
8601679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true));
861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
863a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
865543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
866543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
867543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
868543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
869543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
872264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        if (!isFullscreenMode()) {
873264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project            outInsets.contentTopInsets = outInsets.visibleTopInsets;
874264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        }
8759e347d3d448e48229c46aad394ec9bd60cd5807bsatok        KeyboardView inputView = mKeyboardSwitcher.getInputView();
8769e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
8779e347d3d448e48229c46aad394ec9bd60cd5807bsatok        if (inputView != null && mKeyboardSwitcher.isInputViewShown()) {
8789e347d3d448e48229c46aad394ec9bd60cd5807bsatok            final int x = 0;
8799e347d3d448e48229c46aad394ec9bd60cd5807bsatok            int y = 0;
8809e347d3d448e48229c46aad394ec9bd60cd5807bsatok            final int width = inputView.getWidth();
8819e347d3d448e48229c46aad394ec9bd60cd5807bsatok            int height = inputView.getHeight() + EXTENDED_TOUCHABLE_REGION_HEIGHT;
8829e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (mCandidateViewContainer != null) {
8839e347d3d448e48229c46aad394ec9bd60cd5807bsatok                ViewParent candidateParent = mCandidateViewContainer.getParent();
8849e347d3d448e48229c46aad394ec9bd60cd5807bsatok                if (candidateParent instanceof FrameLayout) {
88500eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                    FrameLayout fl = (FrameLayout) candidateParent;
88600eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                    if (fl != null) {
88700eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        // Check frame layout's visibility
88800eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        if (fl.getVisibility() == View.INVISIBLE) {
88900eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                            y = fl.getHeight();
89000eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                            height += y;
89100eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        } else if (fl.getVisibility() == View.VISIBLE) {
89200eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                            height += fl.getHeight();
89300eb3658734078df46b6fe88b8b6aa8b79d327c9Tadashi G. Takaoka                        }
8949e347d3d448e48229c46aad394ec9bd60cd5807bsatok                    }
8959e347d3d448e48229c46aad394ec9bd60cd5807bsatok                }
8969e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
8979e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
8989e347d3d448e48229c46aad394ec9bd60cd5807bsatok                Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height);
8999e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
9006845da8d7b940018c4ef77646f0028d131ed2753satok            outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
9019e347d3d448e48229c46aad394ec9bd60cd5807bsatok            outInsets.touchableRegion.set(x, y, width, height);
9029e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
904a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
906979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
907458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
908458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
909979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
910979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
911458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
912979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
913979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
914979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
915979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
916979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
917979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
918979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
919979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
922e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
923e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
924e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
9256e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
9266e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
927e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
928e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
929923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
930923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
931923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
932923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
933923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
934923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
936e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
937e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
938e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
939e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
940e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
941e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
942e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
943e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
944e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
945e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
946e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
947e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
948e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
949e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
950e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
951e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
952e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
957409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
9589fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
9599fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
963923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
966979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
972b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9741c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
975e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
976b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9771c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
978b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9791c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9801c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void swapPunctuationAndSpace() {
982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
985923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
986571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastTwo.charAt(0) == Keyboard.CODE_SPACE
987571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && isSentenceSeparator(lastTwo.charAt(1))) {
988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
992b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9939a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
994923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
9961c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
9974ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    private void reswapPeriodAndSpace() {
9984ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        final InputConnection ic = getCurrentInputConnection();
9994ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (ic == null) return;
10004ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
10014ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastThree != null && lastThree.length() == 3
1002571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(0) == Keyboard.CODE_PERIOD
1003571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1004571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_PERIOD) {
10054ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.beginBatchEdit();
10064ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.deleteSurroundingText(3, 0);
10074ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.commitText(" ..", 1);
10084ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.endBatchEdit();
1009b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10104ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
10114ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
10124ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void doubleSpace() {
1014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //if (!mAutoPunctuate) return;
1015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
1019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
1020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
1021571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1022571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
1023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1026923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1027b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10289a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1029923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1030923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1031a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
103241a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
103341a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
103441a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
103541a519729505a877844f2c57a33509c302dddbceKen Wakasa
103641a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
103741a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
103841a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10394ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1040571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1041571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
104241a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
104341a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
104441a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
104541a519729505a877844f2c57a33509c302dddbceKen Wakasa
10469a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
10479a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
10489a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
10499a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
10509a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10519a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1052571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
10539a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
10549a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
10559a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
10569a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
10596558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
10606558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1061d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1062923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1063923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1066923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1067923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1068923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1070923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1072a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1073e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
10749a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10752fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (!mConfigEnableShowSubtypeSettings) {
10762fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                showSubtypeSelectorAndSettings();
10772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
10789a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
10799a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10809a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10819a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10829a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10839a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10849a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1085e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10869a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10879502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
108879efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10899a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10909a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10919a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10929a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10939a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10949a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10959a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
10969a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
10979a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10989a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10995f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
11005a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11018aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1103571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1107b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1108b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1110571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
11114189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
11124189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
11134189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
11144189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1115571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
11164189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
11174189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!distinctMultiTouch)
1118b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
11194189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1120e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
11214189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
11224189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!distinctMultiTouch)
1123b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
11244189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1125571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
11264189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
11274189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
11284189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11294189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1130e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1131e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
11324189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1133e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1134e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
11354189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1136571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_NEXT_LANGUAGE:
11374189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, true);
11384189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1139571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_PREV_LANGUAGE:
11404189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, false);
11414189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1142571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1143b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
11444189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
114520cdb37bd062ae6cb6d42ad6229a19733476cd55satok        case Keyboard.CODE_VOICE:
114620cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
11474189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1148571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
114945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
11504189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
11514189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
1152571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (primaryCode != Keyboard.CODE_ENTER) {
11534189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                mJustAddedAutoSpace = false;
11544189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11554189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            RingCharBuffer.getInstance().push((char)primaryCode, x, y);
11564189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnInputChar();
11574189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (isWordSeparator(primaryCode)) {
11584189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleSeparator(primaryCode);
11594189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
11604189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleCharacter(primaryCode, keyCodes);
11614189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11624189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Cancel the just reverted state
1163c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1165b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1166dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1167dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1169a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11705a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11718aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1172409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.commitVoiceInput();
1173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1175979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        abortCorrection(false);
1176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
117755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
117841a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1181b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11825f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
1183c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
11849a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAddedAutoSpace = false;
1185dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11885a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11898aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
119083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11915f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
119283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
119383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1195409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.logAndRevertVoiceInput()) return;
11964f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1197504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1198504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1199979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1200979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1201409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleBackspace();
12024f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1203504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
12049fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
12119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mHasValidSuggestions = false;
1212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1213d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
1214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1220d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1221504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1223979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
1224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1225979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1227504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1228504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1229504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1230dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
12326558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
12336558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
123455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
12356558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
12366558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
12376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
12386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
12396558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
12406558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
12416558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12436558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
12446558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12456558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1248c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
1249979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
125245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
125345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
125445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int navigationFlags =
125545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
125645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & navigationFlags) == 0) {
125745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
125845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
125945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
126045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
126145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
126245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
126345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
126445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
126545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
126645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
126745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
126845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
126945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
127045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
127145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
127245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
127345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
127445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
127545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
1276979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void abortCorrection(boolean force) {
1277979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (force || TextEntryState.isCorrecting()) {
1278ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            TextEntryState.onAbortCorrection();
1279ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setCandidatesViewShown(isCandidateStripVisible());
1280979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            getCurrentInputConnection().finishComposingText();
1281b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1284a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleCharacter(int primaryCode, int[] keyCodes) {
1286409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleCharacter();
12874f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1288b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) {
1289b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            abortCorrection(false);
1290b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12914f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1292e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
12939fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
12949fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (!mHasValidSuggestions) {
12959fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mHasValidSuggestions = true;
1296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1297979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                saveWordInHistory(mBestWord);
1298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
1299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13011679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1302f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1303eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1304eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1305eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1306eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1307e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1308e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1309e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1310e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1311e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
131212a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
131312a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1314e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
13158aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
131612a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
131712a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1318979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13209fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1321f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1322f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
13230b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1325e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
1326e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mWord.add(code, keyCodes);
1327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
13291c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
13301c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1331b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
13321c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1334923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1335d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1337e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1338923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1339b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1340979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
1341e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        TextEntryState.typedCharacter((char) code, isWordSeparator(code));
1342923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1344923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleSeparator(int primaryCode) {
1345409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleSeparator();
13464f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
134755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
13486558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1349d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
13506558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
13516558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1352923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
13541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1356923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1357979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            abortCorrection(false);
1358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13599fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1361a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1363923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1364c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            if (mAutoCorrectOn && primaryCode != '\'' && !mJustReverted) {
1365979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                pickedDefault = pickDefaultSuggestion();
13669a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // Picked the suggestion by the space key.  We consider this
13679a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // as "added an auto space".
1368571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                if (primaryCode == Keyboard.CODE_SPACE) {
13699a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                    mJustAddedAutoSpace = true;
13709a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                }
1371923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1372923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1373923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1375571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (mJustAddedAutoSpace && primaryCode == Keyboard.CODE_ENTER) {
13769a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            removeTrailingSpace();
13779a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = false;
13789a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)primaryCode);
13804ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
13814ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // Handle the case of ". ." -> " .." with auto-space if necessary
13824ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // before changing the TextEntryState.
1383979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1384571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode == Keyboard.CODE_PERIOD) {
13854ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            reswapPeriodAndSpace();
13864ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13874ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1388923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) primaryCode, true);
1389979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1390571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode != Keyboard.CODE_ENTER) {
1391923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            swapPunctuationAndSpace();
13929fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            doubleSpace();
1394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1395979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
139655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
139755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
139855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
13994ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                if (ic != null) {
14004ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    CorrectionInfo correctionInfo = new CorrectionInfo(
14014ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                            mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
14024ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    ic.commitCorrection(correctionInfo);
14034ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                }
140455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
140555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
140655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
140755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1409b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1410923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1412923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1414466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1417409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleClose();
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
14191679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
14201679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
14211679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
1423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1425979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void saveWordInHistory(CharSequence result) {
1426979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mWord.size() <= 1) {
1427979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mWord.reset();
1428979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1430979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Skip if result is null. It happens in some edge case.
1431979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextUtils.isEmpty(result)) {
1432979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1434979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1435979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
1436979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final String resultCopy = result.toString();
1437979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        TypedWordAlternatives entry = new TypedWordAlternatives(resultCopy,
1438979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                new WordComposer(mWord));
1439979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.add(entry);
1440923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1441923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14429fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isSuggestionsRequested() {
1443c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1444c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1445923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1446a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
14477599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private boolean isShowingPunctuationList() {
14487e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        return mSuggestPuncList == mCandidateView.getSuggestions();
14497599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14507599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14519fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isShowingSuggestionsStrip() {
14527599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
14537599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
14547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
14557599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14567599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCandidateStripVisible() {
1458b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1459b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
14609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isCorrecting())
14619fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14629fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
14639fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
14649fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
14659fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14669fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1468923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1469409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
14705a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        mHandler.post(new Runnable() {
14715a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
14725a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            public void run() {
14735a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                if (DEBUG) {
14745a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    Log.d(TAG, "Switch to keyboard view.");
14755a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                }
14765a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                View v = mKeyboardSwitcher.getInputView();
14775a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                if (v != null) {
14785a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    // Confirms that the keyboard view doesn't have parent view.
14795a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    ViewParent p = v.getParent();
14805a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    if (p != null && p instanceof ViewGroup) {
14815a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                        ((ViewGroup) p).removeView(v);
14825a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    }
14835a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    setInputView(v);
14845a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                }
14855a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                setCandidatesViewShown(isCandidateStripVisible());
14865a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                updateInputViewShown();
14875a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
14885a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
14895a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        });
1490466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1491466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1492409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14937e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1494466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1495466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1497409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.getAndResetIsShowingHint()) {
1498466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1499466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1500466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1501466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
15027e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
15039ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
15049ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
15059ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
15069ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1507466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1508466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1509466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1510409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
15111679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(null);
15121b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
15149fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1515409220583333bdf06290dd9fd42f91b5c0d1b11asatok                && !mVoiceConnector.isVoiceInputHighlighted()) {
1516923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1518466741d8a78965b8509bf527344f289e50873092Mike LeBeau
15199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1520ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1523979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1524979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1525979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
15267e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords.Builder getTypedSuggestions(WordComposer word) {
15279ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka        return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null);
1528979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1529979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1530979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showCorrections(WordAlternatives alternatives) {
15311679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(null);
15327e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = alternatives.getAlternatives();
15337e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
15347e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), alternatives.getOriginalWord());
1535979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1536979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1537979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
1538979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // TODO Maybe need better way of retrieving previous word
1539e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1540979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mWordSeparators);
15417e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
15429ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
15441b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani        int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
15451679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
15461b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1547378a1b516d867671d292900c5d42aef3a0dc1556Ken Wakasa        boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
15486f7218627eda110a8454053f8ecb7b80edfdc8cesatok                && mSuggest.hasAutoCorrection();
1549a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If we're in basic correct
1551a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
1552979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                (preferCapitalization()
1553979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                        && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
1554979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1555979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1556923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1557923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15584a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1559979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1560979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !TextEntryState.isCorrecting();
1561979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1562a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1563a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1564f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1565f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1566f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1567f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1568f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1569a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
15709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
15719fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
15729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
15739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (previousSuggestions == mSuggestPuncList)
15749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
15759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
15769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
15777e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1578979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
15794a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
15807e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
15817e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
15827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
158314e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
158482411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
158582411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
15867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1587923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1588923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1589923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1590923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1591923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1592923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1593ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1596979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean pickDefaultSuggestion() {
1597923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1598d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1599d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1600923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1601923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16026780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1603923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
1604923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
160555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
16069468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1607979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1608979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1609979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1611979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
16157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
1616409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
16174f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1618979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final boolean correcting = TextEntryState.isCorrecting();
16199a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
16209a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
16229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
16231b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
16241b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
16251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1626923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1627923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1628923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1629923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1630923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1631923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1632923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1633b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
16349a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16359a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16369a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1637923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16396a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
16406a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
1641979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0))
1642979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || isSuggestedPunctuation(suggestion.charAt(0)))) {
1643979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1644979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1645979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
16467e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
164755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1648a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1649a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1650a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
16519a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16529a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16539a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
16546a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
16556a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
16569a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
165755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
16589468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
16590c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1660979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1661979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1662979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToBigramDictionary(suggestion, 1);
16630c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1664979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
16657e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1666923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1667923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1668979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mAutoSpace && !correcting) {
1669923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendSpace();
16709a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1671923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1672979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1673b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        final boolean showingAddToDictionaryHint = index == 0 && mCorrectionMode > 0
1674b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion)
1675b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion.toString().toLowerCase());
1676b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1677979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!correcting) {
1678b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1679b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1680b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1681571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true);
1682ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1683b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        } else if (!showingAddToDictionaryHint) {
1684364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1685979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1686b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1687d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1688979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1689b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
169066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
169166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16929a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16939a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16949a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1695923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1696a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1697979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1698979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1699979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1700979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1701979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1702979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
170355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1704b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1705b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
17061679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1709409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.rememberReplacedWord(suggestion, mWordSeparators);
1710979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1712979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        saveWordInHistory(suggestion);
17139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mHasValidSuggestions = false;
1714923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1715b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.setPreferredLetters(null);
1716923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1717923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1718b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    /**
1719b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * Tries to apply any typed alternatives for the word if we have any cached alternatives,
1720b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * otherwise tries to find new corrections and completions for the word.
1721b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @param touching The word that the cursor is touching, with position information
1722b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @return true if an alternative was found, false otherwise.
1723b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     */
1724e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) {
1725b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // If we didn't find a match, search for result in typed word history
1726b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordComposer foundWord = null;
1727b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordAlternatives alternatives = null;
1728b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        for (WordAlternatives entry : mWordHistory) {
1729e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
1730b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                if (entry instanceof TypedWordAlternatives) {
1731b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    foundWord = ((TypedWordAlternatives) entry).word;
1732b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
1733b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                alternatives = entry;
1734b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                break;
1735b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1736b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
17371b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // If we didn't find a match, at least suggest corrections.
1738b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord == null
1739e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                && (mSuggest.isValidWord(touching.mWord)
1740e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
1741b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            foundWord = new WordComposer();
1742e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            for (int i = 0; i < touching.mWord.length(); i++) {
1743e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                foundWord.add(touching.mWord.charAt(i), new int[] {
1744e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    touching.mWord.charAt(i)
1745b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                });
1746b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1747e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
1748b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1749b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // Found a match, show suggestions
1750b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord != null || alternatives != null) {
1751b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (alternatives == null) {
1752e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                alternatives = new TypedWordAlternatives(touching.mWord, foundWord);
1753b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1754b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            showCorrections(alternatives);
1755b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (foundWord != null) {
1756b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord = new WordComposer(foundWord);
1757b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            } else {
1758b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord.reset();
1759b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1760b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return true;
1761b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1762b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return false;
1763b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
1764b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1765979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void setOldSuggestions() {
1766409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setShowingVoiceSuggestions(false);
1767b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
1768b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return;
1769b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1770979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        InputConnection ic = getCurrentInputConnection();
1771979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (ic == null) return;
17729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1773b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Extract the selected or touching text
1774e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
1775b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    mLastSelectionStart, mLastSelectionEnd, mWordSeparators);
1776979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1777e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (touching != null && touching.mWord.length() > 1) {
1778b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.beginBatchEdit();
1779979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1780409220583333bdf06290dd9fd42f91b5c0d1b11asatok                if (!mVoiceConnector.applyVoiceAlternatives(touching)
1781409220583333bdf06290dd9fd42f91b5c0d1b11asatok                        && !applyTypedAlternatives(touching)) {
1782b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    abortCorrection(true);
1783b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                } else {
1784979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    TextEntryState.selectedForCorrection();
1785e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    EditingUtils.underlineWord(ic, touching);
1786979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
1787b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1788b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.endBatchEdit();
1789979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } else {
1790979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                abortCorrection(true);
1791ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                setPunctuationSuggestions();  // Show the punctuation suggestions list
1792979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1793979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1794979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            abortCorrection(true);
1795979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1796979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1797979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1798ca26f20fa4903de46e374babbfba8c8a1a5cac93satok    private void setPunctuationSuggestions() {
17997e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(mSuggestPuncList);
18009fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
18016a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
18026a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1803979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToDictionaries(CharSequence suggestion, int frequencyDelta) {
1804979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1805979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1806979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1807979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1808979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1809979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1810979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1811979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1812979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1813979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param addToBigramDictionary true if it should be added to bigram dictionary if possible
1814979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1815979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1816979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            boolean addToBigramDictionary) {
1817979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
18180c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
18190c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
18200c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1821979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1822979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1823979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1824979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1825e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
1826e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || (!mSuggest.isValidWord(suggestion.toString())
1827e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
1828e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1829e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1830979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1831e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1832e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1833e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    mSentenceSeparators);
1834e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1835e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1836979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
183732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
183832e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
183932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCursorTouchingWord() {
1841923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1842923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
184655b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toLeft.charAt(0))
184755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toLeft.charAt(0))) {
1848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1850a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
185155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toRight.charAt(0))
185255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toRight.charAt(0))) {
1853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1855923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1857a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1858dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1859dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1860dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1861dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1862dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
18659fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions && length > 0) {
1866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1867c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = true;
1868504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1871504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1872504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
1873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
187630be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
187730be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
187830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
187930be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
188030be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1881504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1882504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
188330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
188430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                TextEntryState.typedCharacter(punctuation.charAt(0), true);
188530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
188630be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1887504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
188830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mHasValidSuggestions = true;
1889504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1890504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1891504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1892d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1893923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1894923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1895c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1896923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1897923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1900923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1902a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
1904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
1905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
1906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1907923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1908979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSentenceSeparator(int code) {
1909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mSentenceSeparators.contains(String.valueOf((char)code));
1910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void sendSpace() {
1913571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
1914b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1916923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1917923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
19180b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1919923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1921c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
1922c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1923c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
19244ab730dbd34fad323063f2ffd31ce33de746668dsatok        toggleLanguage(true, true);
19254ab730dbd34fad323063f2ffd31ce33de746668dsatok    }
19264ab730dbd34fad323063f2ffd31ce33de746668dsatok
19274ab730dbd34fad323063f2ffd31ce33de746668dsatok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
19283f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani    private void toggleLanguage(boolean reset, boolean next) {
1929de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
19304ab730dbd34fad323063f2ffd31ce33de746668dsatok            mSubtypeSwitcher.toggleLanguage(reset, next);
19314ab730dbd34fad323063f2ffd31ce33de746668dsatok        }
19324ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1933b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19348b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final EditorInfo attribute = getCurrentInputEditorInfo();
1935c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int mode = initializeInputAttributesAndGetMode((attribute != null)
1936c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                ? attribute.inputType : 0);
1937d98c20b036ff02f99406dabb8cc4fdf4a51cd6c4Tadashi G. Takaoka        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
1938409220583333bdf06290dd9fd42f91b5c0d1b11asatok        switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
1939409220583333bdf06290dd9fd42f91b5c0d1b11asatok                mVoiceConnector.isVoiceButtonOnPrimary());
19400ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
1941b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
194236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
194336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
19445a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
194536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
194636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            String key) {
19470ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
19489502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
194936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = true;
19509502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) {
19519502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            mReCorrectionEnabled = sharedPreferences.getBoolean(
19529502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                    Settings.PREF_RECORRECTION_ENABLED,
1953458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                    mResources.getBoolean(R.bool.default_recorrection_enabled));
195436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
195536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
195636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
19575a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
19588aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
1959363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        if (mConfigSwipeDownDismissKeyboardEnabled)
1960363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onPress(int primaryCode) {
1965cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1966cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1967cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1968cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
19691679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19701679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1971571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1972b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.onPressShift();
1973e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19746c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
197540a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
19766c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1977681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19805a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onRelease(int primaryCode) {
19821679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19833f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
19841679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        switcher.keyReleased();
19851679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1986571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1987889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka            switcher.onReleaseShift();
1988e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19896c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
199040a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1992a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1993a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1994123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
1995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1998123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
1999123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
2000123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
2001123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
2002123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
2003123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
2004923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2005923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
2006923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
2008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
2009923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2010923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
2013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
2014923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2015923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
2018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
2019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
2020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2021979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mKeyboardSwitcher.getInputView() != null) {
2022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
2023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSoundOn && !mSilentMode) {
2026923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
2027923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
2028923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
2029923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
2030571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
2031923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
2032923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2033571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
2034923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
2035923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2036571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
2037923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
2038923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2039923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2040923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
2041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2044409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
2045923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mVibrateOn) {
2046923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
2047923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
20481679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
20491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
20501679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
2051979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
205266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
2053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2054923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2055923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
205671c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public void promoteToUserDictionary(String word, int frequency) {
205734386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
205834386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
205934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
206034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
206171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
20626516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
20636516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
20646516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
206571c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public boolean getPopupOn() {
2066979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mPopupOn;
2067979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2068979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2069e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
2070e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
2071e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
2072e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                && !mInputTypeNoAutoCorrect && mHasDictionary;
207332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled)
2074e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
207532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani                : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
2076979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mCorrectionMode = (mBigramSuggestionEnabled && mAutoCorrectOn && mAutoCorrectEnabled)
2077979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2078e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2079e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2080e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2081e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2082e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
20830ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
208432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
20850ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSuggest.setAutoTextEnabled(mQuickFixes
20864ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
208732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
208832e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
20897599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private void updateSuggestionVisibility(SharedPreferences prefs) {
2090458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
20917599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
20929502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2093458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
20947599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2095458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
20967599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
20977599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
20987599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
20997599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
21007599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
21017599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2102466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
21039502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
2104466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2105466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2106bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
21079502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
2108bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2109bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2110507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
2111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2113466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2118507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private void loadSettings(EditorInfo attribute) {
2119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Get the settings preferences
212027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
21214174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasa        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
21224174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasa        mVibrateOn = vibrator != null && vibrator.hasVibrator()
21239502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
21249502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, false);
2125728115493e14f84d5f02a4812c8086a378813364Jean Chalard
2126728115493e14f84d5f02a4812c8086a378813364Jean Chalard        mPopupOn = isPopupEnabled(prefs);
21279502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
212889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
2129a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
213027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
213127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
21321b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
2133466741d8a78965b8509bf527344f289e50873092Mike LeBeau
213427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector.loadSettings(attribute, prefs);
2135409220583333bdf06290dd9fd42f91b5c0d1b11asatok
2136e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
21370ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
213827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        updateSuggestionVisibility(prefs);
213927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.getInstance().loadSettings();
214036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
214136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2142b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    /**
21431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka     *  Load Auto correction threshold from SharedPreferences, and modify mSuggest's threshold.
2144b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda     */
21451b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private void loadAndSetAutoCorrectionThreshold(SharedPreferences sp) {
2146b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // When mSuggest is not initialized, cannnot modify mSuggest's threshold.
2147b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (mSuggest == null) return;
21481b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When auto correction setting is turned off, the threshold is ignored.
2149b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (!isAutoCorrectEnabled(sp)) return;
2150b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
21511b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
21521b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
21539ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
21541b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String[] autoCorrectionThresholdValues = mResources.getStringArray(
21559ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.array.auto_correction_threshold_values);
21561b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When autoCrrectionThreshold is greater than 1.0, auto correction is virtually turned off.
21571b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        double autoCorrectionThreshold = Double.MAX_VALUE;
2158b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        try {
21591b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
21601b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
21611b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                autoCorrectionThreshold = Double.parseDouble(
21621b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                        autoCorrectionThresholdValues[arrayIndex]);
2163b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda            }
2164b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        } catch (NumberFormatException e) {
21651b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            // Whenever the threshold settings are correct, never come here.
21661b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            autoCorrectionThreshold = Double.MAX_VALUE;
21671b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            Log.w(TAG, "Cannot load auto correction threshold setting."
21681b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
21691b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + ", autoCorrectionThresholdValues: "
21701b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + Arrays.toString(autoCorrectionThresholdValues));
2171b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        }
2172b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // TODO: This should be refactored :
21731b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        //           setAutoCorrectionThreshold should be called outside of this method.
21741b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
2175b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2176b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2177728115493e14f84d5f02a4812c8086a378813364Jean Chalard    private boolean isPopupEnabled(SharedPreferences sp) {
2178728115493e14f84d5f02a4812c8086a378813364Jean Chalard        final boolean showPopupOption = getResources().getBoolean(
2179728115493e14f84d5f02a4812c8086a378813364Jean Chalard                R.bool.config_enable_show_popup_on_keypress_option);
2180728115493e14f84d5f02a4812c8086a378813364Jean Chalard        if (!showPopupOption) return mResources.getBoolean(R.bool.config_default_popup_preview);
2181728115493e14f84d5f02a4812c8086a378813364Jean Chalard        return sp.getBoolean(Settings.PREF_POPUP_ON,
2182728115493e14f84d5f02a4812c8086a378813364Jean Chalard                mResources.getBoolean(R.bool.config_default_popup_preview));
2183728115493e14f84d5f02a4812c8086a378813364Jean Chalard    }
2184728115493e14f84d5f02a4812c8086a378813364Jean Chalard
218589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    private boolean isQuickFixesEnabled(SharedPreferences sp) {
218689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showQuickFixesOption = mResources.getBoolean(
218789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_quick_fixes_option);
218889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showQuickFixesOption) {
218989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
219089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
219189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
219289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_quick_fixes));
219389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    }
219489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard
2195b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
21961b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
21971b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
21989ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
21991b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String autoCorrectionOff = mResources.getString(
22009ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.string.auto_correction_threshold_mode_index_off);
22011b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
2202b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2203b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2204b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
220589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showBigramSuggestionsOption = mResources.getBoolean(
220689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_bigram_suggestions_option);
220789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showBigramSuggestionsOption) {
220889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
220989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
221089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
221189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_bigram_suggestions));
2212b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2213b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
22146a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
22157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (mSuggestPuncs != null || mSuggestPuncList != null)
22167e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            return;
22177e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = new SuggestedWords.Builder();
22187e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        String puncs = mResources.getString(R.string.suggested_punctuations);
22197e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (puncs != null) {
22207e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            for (int i = 0; i < puncs.length(); i++) {
22217e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                builder.addWord(puncs.subSequence(i, i + 1));
22226a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
22236a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
22247e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncList = builder.build();
22257e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncs = puncs;
22266a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
22276a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2228979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSuggestedPunctuation(int code) {
2229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestPuncs.contains(String.valueOf((char)code));
2230979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2231979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
22322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
223385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
223485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
223585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
223685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
223785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
223885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
223985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22402fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
22412fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
22422fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
22432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
224485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
22452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    Intent intent = new Intent(
22462fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
22472fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
22482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
22492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
22502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    intent.putExtra(android.provider.Settings.EXTRA_INPUT_METHOD_ID,
22512fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            mInputMethodId);
22522fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
22532fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2254aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2255aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2256aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
22572fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
22582fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
225985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
226085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
22612fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22632fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
226485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
226585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
226685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
226785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
226885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
226985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22705a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
227485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
22752fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    launchSettings();
22762fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
227785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
22782fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    mImm.showInputMethodPicker();
22792fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
228285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
228385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
22842fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
22852fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
228685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
228785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
22882fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
22892fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
22902fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
22912fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
229285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
229385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2295a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
2298979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
2299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23057e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
23067e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2308a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
23139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
23159fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mHasValidSuggestions=" + mHasValidSuggestions);
2316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
2317923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoSpace=" + mAutoSpace);
23181b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
2320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
2321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
2322979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        p.println("  mPopupOn=" + mPopupOn);
2323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
23246e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2326a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2331a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2334923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2335923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2337923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2338923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2341923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
234234386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
23430ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    @Override
23440ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
23454ab730dbd34fad323063f2ffd31ce33de746668dsatok        SubtypeSwitcher.getInstance().updateSubtype(subtype);
23460ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
2347923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2348