LatinIME.java revision 85996b472a0ec5fc31e57c52aa46c8c7794689bb
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;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
444174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasaimport android.os.Vibrator;
45bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
47e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
49979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
53e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.Gravity;
5466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
56e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.LayoutInflater;
57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
588e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
598e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Window;
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.WindowManager;
62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
631b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaokaimport android.view.inputmethod.CorrectionInfo;
64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
65466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
66466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedTextRequest;
67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputMethodManager;
690ed7191b4d1013a0b9d2fd1f26733dee7364871dsatokimport android.view.inputmethod.InputMethodSubtype;
709e347d3d448e48229c46aad394ec9bd60cd5807bsatokimport android.widget.FrameLayout;
71e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.HorizontalScrollView;
7240ac45ebdcd71940394dda00371d4847f7db0f26Ken Wakasaimport android.widget.LinearLayout;
73923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
74466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
75466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
76466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.ArrayList;
77b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimodaimport java.util.Arrays;
78466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
79466741d8a78965b8509bf527344f289e50873092Mike LeBeau
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
8355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokapublic class LatinIME extends InputMethodService implements KeyboardActionListener,
84e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        SharedPreferences.OnSharedPreferenceChangeListener {
85466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String TAG = "LatinIME";
86979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
87409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
88910b73127fa207dd26ec8124000262523b0aac0csatok    private static boolean DEBUG = LatinImeLogger.sDBG;
89a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
90fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_SUGGESTIONS = 180;
91fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
92d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    private static final int DELAY_UPDATE_SHIFT_STATE = 300;
939e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
94fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
98d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
99a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1007599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1017599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1027599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1037599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1047599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1057599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1067599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1077599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1087599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1097599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1107599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1117599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1127599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1137599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
114e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1171b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
118a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
120a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12179efbed76f638be298493107fa2d0cd1b5eb529esatok    private InputMethodManager mImm;
1222fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1232fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1242fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
12571c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1260ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
127409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private VoiceIMEConnector mVoiceConnector;
128a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
130979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1312bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1324ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
13336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
134c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
135c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mAutoSpace;
136c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
137c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
138c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
139c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
14071c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
1439fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean mHasValidSuggestions;
144e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1459a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private boolean mJustAddedAutoSpace;
146e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
14766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok    private boolean mReCorrectionEnabled;
148979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mBigramSuggestionEnabled;
149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
152979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mPopupOn;
153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
1546e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
1552fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private boolean mConfigEnableShowSubtypeSettings;
156363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka    private boolean mConfigSwipeDownDismissKeyboardEnabled;
157de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
158de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDurationOfFadeoutLanguageOnSpacebar;
159d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka    private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
160de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka    // For example, to deal with status bar on tablet.
161de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka    private int mKeyboardBottomRowVerticalCorrection;
162409220583333bdf06290dd9fd42f91b5c0d1b11asatok
16379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
16479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
16579efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
166979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
16779efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
16879efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
1697e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestPuncList;
170979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
173c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa    private boolean mJustReverted;
174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
176a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
1782296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
17971c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
182979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /* package */ String mWordSeparators;
183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mSentenceSeparators;
184979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private String mSuggestPuncs;
185409220583333bdf06290dd9fd42f91b5c0d1b11asatok    // TODO: Move this flag to VoiceIMEConnector
18681c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
187466741d8a78965b8509bf527344f289e50873092Mike LeBeau
188dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
189dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
190979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mRefreshKeyboardRequired;
191dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
19271c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
193979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
194979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public abstract static class WordAlternatives {
195979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        protected CharSequence mChosenWord;
1964f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
197979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives() {
198979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
199979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
200979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
201979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives(CharSequence chosenWord) {
202979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mChosenWord = chosenWord;
203979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
204979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
205979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public int hashCode() {
207979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord.hashCode();
208979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
209979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
210979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public abstract CharSequence getOriginalWord();
211979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
212979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getChosenWord() {
213979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord;
214979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
215979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2167e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public abstract SuggestedWords.Builder getAlternatives();
217979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
218979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
219979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public class TypedWordAlternatives extends WordAlternatives {
220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        private WordComposer word;
221979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
222979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives() {
223979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
224979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
225979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
226979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
227979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            super(chosenWord);
228979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            word = wordComposer;
229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
230979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
231979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
232979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getOriginalWord() {
233979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return word.getTypedWord();
234979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
235979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
236979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
2377e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public SuggestedWords.Builder getAlternatives() {
238979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return getTypedSuggestions(word);
239979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
240979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
24136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
242571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
243d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
244409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
245d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
247d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
248d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
249de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
250de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
251d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
253923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
254de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
255de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
256923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
257d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
258d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
259d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
260d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
261d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                setOldSuggestions();
262d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
263d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
264de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
267e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mVoiceConnector.handleVoiceResults(preferCapitalization()
268de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
269de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
270de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
271de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
27266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
273d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
27466432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
275de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        mConfigDurationOfFadeoutLanguageOnSpacebar);
277de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
278de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
279de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
28066432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
281d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
282d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), DELAY_UPDATE_SUGGESTIONS);
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
294d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
295d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
296d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
297d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
298d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
299d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
300d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
302d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                    DELAY_UPDATE_OLD_SUGGESTIONS);
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
304d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
306d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
309d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), DELAY_UPDATE_SHIFT_STATE);
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
320d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
321de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
322d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
323de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
324de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
325de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
326de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
327de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                final LatinKeyboard keyboard = inputView.getLatinKeyboard();
328de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
329de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
330d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
331d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
332de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is always displayed when the delay is negative.
333d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
334de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
335de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                            mConfigDelayBeforeFadeoutLanguageOnSpacebar);
336de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
337de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
338de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
339d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3417e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3427e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
34327d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
34427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
34527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
34627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
34727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
348363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
349923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
350363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
35179efbed76f638be298493107fa2d0cd1b5eb529esatok        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
3522fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getApplicationInfo().packageName);
3530ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3540ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
355363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
356363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
357363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
358fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
359fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // If the option should not be shown, do not read the recorrection preference
360fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        // but always use the default setting defined in the resources.
361fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
362fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard            mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
363fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard                    res.getBoolean(R.bool.default_recorrection_enabled));
364fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        } else {
365fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard            mReCorrectionEnabled = res.getBoolean(R.bool.default_recorrection_enabled);
366fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard        }
367fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
3682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        mConfigEnableShowSubtypeSettings = res.getBoolean(
3692fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                R.bool.config_enable_show_subtype_settings);
370363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
371363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                R.bool.config_swipe_down_dismiss_keyboard_enabled);
372de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
373de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_delay_before_fadeout_language_on_spacebar);
374de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
375de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_duration_of_fadeout_language_on_spacebar);
376d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
37766432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
378de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka        mKeyboardBottomRowVerticalCorrection = (int)res.getDimension(
379de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                R.dimen.keyboard_bottom_row_vertical_correction);
380979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3819502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
382979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
3839502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
384979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
3850ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
386979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
387979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
3889502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
389979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
390979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
391979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
392363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
3936a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
394b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
395923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // register to receive ringer mode changes for silent mode
396923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
39827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
3993f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        prefs.registerOnSharedPreferenceChangeListener(this);
400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
40136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
402979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
403458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa     * Returns a main dictionary resource id
404458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa     * @return main dictionary resource id
405979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
406458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa    public static int getMainDictionaryResourceId(Resources res) {
407458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final String MAIN_DIC_NAME = "main";
408979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        String packageName = LatinIME.class.getPackage().getName();
409458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
410979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
411979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
4120ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
4130ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
4144ab730dbd34fad323063f2ffd31ce33de746668dsatok        String locale = mSubtypeSwitcher.getInputLocaleStr();
41536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4160ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
41736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
41836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
41936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
42027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
42189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        mQuickFixes = isQuickFixesEnabled(prefs);
422979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
423458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
424458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        int mainDicResId = getMainDictionaryResourceId(res);
425458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSuggest = new Suggest(this, mainDicResId);
4261b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
427e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
4280ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mUserDictionary = new UserDictionary(this, locale);
429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
430e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
431e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4322bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
433e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
434e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
43534386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
436e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
437e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
438e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
439e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
440e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
441458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mWordSeparators = res.getString(R.string.word_separators);
442458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSentenceSeparators = res.getString(R.string.sentence_separators);
44336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4440ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.changeSystemLocale(savedLocale);
445923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
44636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
447466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
448466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
449e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
450e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
451e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
452979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
453923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
454409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.destroy();
455979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
456979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
462dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
463b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
464b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
465466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
466466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
467466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
468b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
4692fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
4702fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
471b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
4728b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
47381c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
474923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
475bbd651a00898dabf6b2ae0e715d99953ea81063fLuca Zanolin        mVoiceConnector.onConfigurationChanged(conf);
47681c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
478b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
479923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
4818d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
486e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
487e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
488e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
489e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (container.getPaddingRight() != 0) {
490e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            HorizontalScrollView scrollView =
491e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                    (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view);
492e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
493e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            container.setGravity(Gravity.CENTER_HORIZONTAL);
494e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
495e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
498e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
50147f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    private static boolean isPasswordVariation(int variation) {
502e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
503e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
504e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
50547f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    }
50647f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins
50747f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    private static boolean isEmailVariation(int variation) {
508e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
509e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
51047f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    }
51147f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins
512a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
51445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
51545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5168e09172df1bb176cc899940862c56bed9b9aec4esatok
517910b73127fa207dd26ec8124000262523b0aac0csatok        if(DEBUG) {
518910b73127fa207dd26ec8124000262523b0aac0csatok            Log.d(TAG, "onStartInputView: " + inputView);
519910b73127fa207dd26ec8124000262523b0aac0csatok        }
520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
521979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5258d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5264ab730dbd34fad323063f2ffd31ce33de746668dsatok
52736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mRefreshKeyboardRequired) {
52836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = false;
529c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            onRefreshKeyboard();
53036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
53136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.newSession(this);
5336c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
534c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
535c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
536c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
537c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.resetVoiceStates(isPasswordVariation(
538c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                attribute.inputType & InputType.TYPE_MASK_VARIATION));
539c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
540c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
541c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
542c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
543c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
544c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
545c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHasValidSuggestions = false;
546c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
547c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mJustAddedAutoSpace = false;
548c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
549c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        loadSettings(attribute);
550c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
551c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.loadKeyboard(mode, attribute.imeOptions,
552c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonEnabled(),
553c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonOnPrimary());
554c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
555c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
556c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
557c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(),
558c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                false /* needsInputViewShown */ );
559c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
560c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
561c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
562c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
563c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
564c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setPreviewEnabled(mPopupOn);
565c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
566c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
567c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        checkReCorrectionOnStart();
568c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
569c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
570c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.onStartInputView(inputView.getWindowToken());
571c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
572de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka        if (mKeyboardBottomRowVerticalCorrection > 0) {
573de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka            final Window window = getWindow().getWindow();
574de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka            if (!(window.getCallback() instanceof ClipTouchEventWindowCallback)) {
575de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                window.setCallback(new ClipTouchEventWindowCallback(
576de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                        window, mKeyboardBottomRowVerticalCorrection));
577de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka            }
578de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka        }
579de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka
580c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
581c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
582c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
583c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private int initializeInputAttributesAndGetMode(int inputType) {
584c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
585c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mAutoSpace = false;
586e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
5879fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
5881b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
5891b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
590dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
591f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka        final int mode;
592c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        switch (inputType & InputType.TYPE_MASK_CLASS) {
593e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_NUMBER:
594e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_DATETIME:
5955a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_NUMBER;
5962c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                break;
597e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_PHONE:
5985a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_PHONE;
599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
600e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_TEXT:
6019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = true;
602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Make sure that passwords are not displayed in candidate view
60347f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isPasswordVariation(variation)) {
6049fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
60647f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isEmailVariation(variation)
607e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
608923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = false;
609923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = true;
611923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
61247f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isEmailVariation(variation)) {
6139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6145a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_EMAIL;
615e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
6169fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_URL;
618e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
6195a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_IM;
620e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
6219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_TEXT;
623e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
6245a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_WEB;
6256c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // If it's a browser edit field and auto correct is not ON explicitly, then
6266c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // disable auto correction, but keep suggestions on.
627c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
628e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                        mInputTypeNoAutoCorrect = true;
6296c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    }
630f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka                } else {
6315a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_TEXT;
632923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
63336ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani
63436ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If NO_SUGGESTIONS is set, don't do prediction.
635c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
6369fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
637e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
63836ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
63936ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If it's not multiline and the autoCorrect flag is not set, then don't correct
640c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
641c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                        (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
642e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
64336ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
644c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
6459fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6461b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    mApplicationSpecifiedCompletionOn = isFullscreenMode();
647923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
648923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
649923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            default:
6505a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_TEXT;
651f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka                break;
652923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
653c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mode;
654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
656b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    private void checkReCorrectionOnStart() {
657d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (!mReCorrectionEnabled) return;
658d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
659d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
660d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (ic == null) return;
661d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        // There could be a pending composing span.  Clean it up first.
662d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        ic.finishComposingText();
663d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
6649fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isShowingSuggestionsStrip() && isSuggestionsRequested()) {
665b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // First get the cursor position. This is required by setOldSuggestions(), so that
666b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // it can pass the correct range to setComposingRegion(). At this point, we don't
6674ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka            // have valid values for mLastSelectionStart/End because onUpdateSelection() has
668b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // not been called yet.
669b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedTextRequest etr = new ExtractedTextRequest();
670b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            etr.token = 0; // anything is fine here
671b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedText et = ic.getExtractedText(etr, 0);
672b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            if (et == null) return;
673b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
674b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionStart = et.startOffset + et.selectionStart;
675b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionEnd = et.startOffset + et.selectionEnd;
676b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
677b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // Then look for possible corrections in a delayed fashion
67855b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) {
679d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateOldSuggestions();
68055b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            }
681b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani        }
682b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    }
683b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
684923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
685923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
686923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
687a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
688979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6891b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
690979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
691409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
692409220583333bdf06290dd9fd42f91b5c0d1b11asatok
6935a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
694d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6954ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
696979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
697466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
698466741d8a78965b8509bf527344f289e50873092Mike LeBeau
699466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
7006495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
7016495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
7025a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
703d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
704d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
705d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
706d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
7076495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
7086495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
7096495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
710466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
711466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
712409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.showPunctuationHintIfNecessary();
713923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
714923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
715923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
716923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
717923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
718923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
719923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
720923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
721466741d8a78965b8509bf527344f289e50873092Mike LeBeau
722466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
723466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
724466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
725466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
726466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
727466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
728466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
729466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
730466741d8a78965b8509bf527344f289e50873092Mike LeBeau
731409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setCursorAndSelection(newSelEnd, newSelStart);
7324f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
7359fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((((mComposing.length() > 0 && mHasValidSuggestions)
7368e09172df1bb176cc899940862c56bed9b9aec4esatok                || mVoiceConnector.isVoiceInputHighlighted()) && (newSelStart != candidatesEnd
7378e09172df1bb176cc899940862c56bed9b9aec4esatok                        || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart)) {
738923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
7399fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
740d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
741923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
742923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
743923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
744923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
746409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.setVoiceInputHighlighted(false);
7479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (!mHasValidSuggestions && !mJustAccepted) {
7489a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            switch (TextEntryState.getState()) {
749e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case ACCEPTED_DEFAULT:
750e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                TextEntryState.reset();
751e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                // $FALL-THROUGH$
752e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case SPACE_AFTER_PICKED:
753e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mJustAddedAutoSpace = false; // The user moved the cursor.
754e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
755e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            default:
756e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
7579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
758923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
759923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
760d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
761466741d8a78965b8509bf527344f289e50873092Mike LeBeau
762979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
763979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
764979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
765466741d8a78965b8509bf527344f289e50873092Mike LeBeau
7669fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isShowingSuggestionsStrip()) {
76766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok            // Don't look for corrections if the keyboard is not visible
7681679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()) {
76966b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                // Check if we should go in or out of correction mode.
7709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                if (isSuggestionsRequested() && !mJustReverted
77166b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
77266b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                                || TextEntryState.isCorrecting())
7739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                                && (newSelStart < newSelEnd - 1 || !mHasValidSuggestions)) {
77466b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
775d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                        mHandler.postUpdateOldSuggestions();
77666b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    } else {
77766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        abortCorrection(false);
77855b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        // Show the punctuation suggestions list if the current one is not
779364da8c618303a7764595d2c15ee034a7671365dKen Wakasa                        // and if not showing "Touch again to save".
7807599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        if (mCandidateView != null && !isShowingPunctuationList()
7817599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                                && !mCandidateView.isShowingAddToDictionaryHint()) {
782ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                            setPunctuationSuggestions();
78355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        }
78466b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    }
785b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
786466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
787466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
788923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
789923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
790c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
791c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
792c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
793c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
794c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
795c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
796c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
797c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
798c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
799c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
8009fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
801c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
802c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
803c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
804c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
805c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
806c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
807c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
808c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
809c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
810c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
811c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
812c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
813c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
814c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
815c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
8169fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
817c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
818c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
819c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
820c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
823979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
8241b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
825979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
826923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
8276e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8286e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8296e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8306e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
831409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.hideVoiceWindow(mConfigurationChanging);
832979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.clear();
833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
834923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8381b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
839979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
840a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
8411b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int count = (applicationSpecifiedCompletions != null)
8421b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    ? applicationSpecifiedCompletions.length : 0;
8431b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            for (int i = 0; i < count; i++) {
844a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8471b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8481b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8491b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
850b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
853a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8547e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8551b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8567e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8577e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
858979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
8597e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
861543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
865543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // TODO: Remove this if we support candidates with hard keyboard
867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
8681679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            super.setCandidatesViewShown(shown
8691679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true));
870923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
872a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
874543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
875543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
876543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
877543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
878543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
879923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
881264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        if (!isFullscreenMode()) {
882264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project            outInsets.contentTopInsets = outInsets.visibleTopInsets;
883264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        }
8849e347d3d448e48229c46aad394ec9bd60cd5807bsatok        KeyboardView inputView = mKeyboardSwitcher.getInputView();
8859e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
8869e347d3d448e48229c46aad394ec9bd60cd5807bsatok        if (inputView != null && mKeyboardSwitcher.isInputViewShown()) {
8879e347d3d448e48229c46aad394ec9bd60cd5807bsatok            final int x = 0;
8889e347d3d448e48229c46aad394ec9bd60cd5807bsatok            int y = 0;
8899e347d3d448e48229c46aad394ec9bd60cd5807bsatok            final int width = inputView.getWidth();
8909e347d3d448e48229c46aad394ec9bd60cd5807bsatok            int height = inputView.getHeight() + EXTENDED_TOUCHABLE_REGION_HEIGHT;
8919e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (mCandidateViewContainer != null) {
8929e347d3d448e48229c46aad394ec9bd60cd5807bsatok                ViewParent candidateParent = mCandidateViewContainer.getParent();
8939e347d3d448e48229c46aad394ec9bd60cd5807bsatok                if (candidateParent instanceof FrameLayout) {
894de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                    final FrameLayout fl = (FrameLayout) candidateParent;
895de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                    // Check frame layout's visibility
896de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                    if (fl.getVisibility() == View.INVISIBLE) {
897de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                        y = fl.getHeight();
898de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                        height += y;
899de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                    } else if (fl.getVisibility() == View.VISIBLE) {
900de59a84029d3d3ec114b5b0f2eca0b3752982fefTadashi G. Takaoka                        height += fl.getHeight();
9019e347d3d448e48229c46aad394ec9bd60cd5807bsatok                    }
9029e347d3d448e48229c46aad394ec9bd60cd5807bsatok                }
9039e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
9049e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
9059e347d3d448e48229c46aad394ec9bd60cd5807bsatok                Log.d(TAG, "Touchable region " + x + ", " + y + ", " + width + ", " + height);
9069e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
9076845da8d7b940018c4ef77646f0028d131ed2753satok            outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
9089e347d3d448e48229c46aad394ec9bd60cd5807bsatok            outInsets.touchableRegion.set(x, y, width, height);
9099e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
911a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
913979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
914458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
915458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
916979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
917979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
918458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
919979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
920979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
921979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
922979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
923979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
924979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
925979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
926979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
927923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
928923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
929e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
930e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
931e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
9326e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
9336e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
934e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
935e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
936923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
943e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
944e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
945e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
946e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
947e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
948e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
949e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
950e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
951e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
952e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
953e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
954e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
955e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
956e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
957e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
958e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
959e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
963923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
964409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
9659fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
9669fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
973979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
975923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
979b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9811c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
982e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
983b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
985b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9861c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9871c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void swapPunctuationAndSpace() {
989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
990923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
991923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
993571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastTwo.charAt(0) == Keyboard.CODE_SPACE
994571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && isSentenceSeparator(lastTwo.charAt(1))) {
995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
998923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
999b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10009a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
10031c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
10044ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    private void reswapPeriodAndSpace() {
10054ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        final InputConnection ic = getCurrentInputConnection();
10064ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (ic == null) return;
10074ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
10084ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastThree != null && lastThree.length() == 3
1009571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(0) == Keyboard.CODE_PERIOD
1010571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1011571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_PERIOD) {
10124ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.beginBatchEdit();
10134ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.deleteSurroundingText(3, 0);
10144ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.commitText(" ..", 1);
10154ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.endBatchEdit();
1016b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10174ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
10184ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
10194ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void doubleSpace() {
1021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //if (!mAutoPunctuate) return;
1022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
1023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
1026923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
1027923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
1028571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1029571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
1030923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1031923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1032923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1033923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1034b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
10359a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1036923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1037923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1038a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
103941a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
104041a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
104141a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
104241a519729505a877844f2c57a33509c302dddbceKen Wakasa
104341a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
104441a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
104541a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10464ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1047571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1048571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
104941a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
105041a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
105141a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
105241a519729505a877844f2c57a33509c302dddbceKen Wakasa
10539a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
10549a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
10559a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
10569a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
10579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10589a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1059571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
10609a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
10619a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
10629a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
10639a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
10666558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
10676558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1068d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1070923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1071923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1072923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1073923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1074923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1075923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1078923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1079a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1080e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
10819a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10822fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (!mConfigEnableShowSubtypeSettings) {
10832fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                showSubtypeSelectorAndSettings();
10842fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
10859a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
10869a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10879a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10889a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10899a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10909a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10919a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1092e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10939a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10949502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
109579efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10969a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10979a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10989a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10999a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
11009a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
11019a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
11029a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
11039a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
11049a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
11059a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
11065f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
11075a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11088aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1110571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1114b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1115b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1117571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
11184189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
11194189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
11204189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
11214189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1122571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
11234189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
11244189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!distinctMultiTouch)
1125b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
11264189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1127e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
11284189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
11294189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!distinctMultiTouch)
1130b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
11314189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1132571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
11334189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
11344189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
11354189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11364189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1137e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1138e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
11394189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1140e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1141e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
11424189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1143571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_NEXT_LANGUAGE:
11444189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, true);
11454189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1146571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_PREV_LANGUAGE:
11474189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, false);
11484189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1149571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1150b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
11514189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
115220cdb37bd062ae6cb6d42ad6229a19733476cd55satok        case Keyboard.CODE_VOICE:
115320cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
11544189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1155571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
115645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
11574189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
11584189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
1159571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (primaryCode != Keyboard.CODE_ENTER) {
11604189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                mJustAddedAutoSpace = false;
11614189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11624189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            RingCharBuffer.getInstance().push((char)primaryCode, x, y);
11634189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnInputChar();
11644189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (isWordSeparator(primaryCode)) {
11654189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleSeparator(primaryCode);
11664189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
11674189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleCharacter(primaryCode, keyCodes);
11684189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11694189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Cancel the just reverted state
1170c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1172b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1173dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1174dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1176a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11775a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11788aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1179409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.commitVoiceInput();
1180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1182979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        abortCorrection(false);
1183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
118455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
118541a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1188b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11895f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
1190c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
11919a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAddedAutoSpace = false;
1192dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11955a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11968aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
119783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11985f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
119983e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
120083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1201923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1202409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.logAndRevertVoiceInput()) return;
12034f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1204504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1205504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1207979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1208409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleBackspace();
12094f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1210504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
12119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
12189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mHasValidSuggestions = false;
1219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1220d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
1221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1227d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1228504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1230979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
1231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1232979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1233923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1234504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1235504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1236504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1237dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
12396558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
12406558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
124155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
12426558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
12436558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
12446558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
12456558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
12466558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
12476558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
12486558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12506558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
12516558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
12526558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1253923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1255c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
1256979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
125945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
126045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
126145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int navigationFlags =
126245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
126345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & navigationFlags) == 0) {
126445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
126545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
126645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
126745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
126845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
126945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
127045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
127145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
127245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
127345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
127445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
127545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
127645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
127745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
127845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
127945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
128045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
128145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
128245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
1283979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void abortCorrection(boolean force) {
1284979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (force || TextEntryState.isCorrecting()) {
1285ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            TextEntryState.onAbortCorrection();
1286ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setCandidatesViewShown(isCandidateStripVisible());
1287979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            getCurrentInputConnection().finishComposingText();
1288b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1291a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleCharacter(int primaryCode, int[] keyCodes) {
1293409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleCharacter();
12944f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1295b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) {
1296b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            abortCorrection(false);
1297b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12984f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1299e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
13009fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
13019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (!mHasValidSuggestions) {
13029fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mHasValidSuggestions = true;
1303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1304979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                saveWordInHistory(mBestWord);
1305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
1306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13081679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1309f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1310eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1311eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1312eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1313eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1314e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1315e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1316e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1317e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1318e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
131912a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
132012a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1321e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
13228aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
132312a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
132412a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1325979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13279fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1328f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1329f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
13300b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1332e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
1333e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mWord.add(code, keyCodes);
1334923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1335923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
13361c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
13371c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1338b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
13391c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1341923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1342d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1344e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1346b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1347979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
1348e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        TextEntryState.typedCharacter((char) code, isWordSeparator(code));
1349923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1350923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1351923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleSeparator(int primaryCode) {
1352409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleSeparator();
13534f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
135455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
13556558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1356d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
13576558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
13586558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1359923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
13611b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1363923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1364979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            abortCorrection(false);
1365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13669fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1368a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1371c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            if (mAutoCorrectOn && primaryCode != '\'' && !mJustReverted) {
1372979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                pickedDefault = pickDefaultSuggestion();
13739a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // Picked the suggestion by the space key.  We consider this
13749a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // as "added an auto space".
1375571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                if (primaryCode == Keyboard.CODE_SPACE) {
13769a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                    mJustAddedAutoSpace = true;
13779a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                }
1378923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1380923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1382571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (mJustAddedAutoSpace && primaryCode == Keyboard.CODE_ENTER) {
13839a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            removeTrailingSpace();
13849a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = false;
13859a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)primaryCode);
13874ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
13884ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // Handle the case of ". ." -> " .." with auto-space if necessary
13894ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // before changing the TextEntryState.
1390979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1391571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode == Keyboard.CODE_PERIOD) {
13924ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            reswapPeriodAndSpace();
13934ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13944ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1395923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) primaryCode, true);
1396979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1397571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode != Keyboard.CODE_ENTER) {
1398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            swapPunctuationAndSpace();
13999fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            doubleSpace();
1401923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1402979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
140355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
140455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
140555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
14064ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                if (ic != null) {
14074ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    CorrectionInfo correctionInfo = new CorrectionInfo(
14084ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                            mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
14094ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    ic.commitCorrection(correctionInfo);
14104ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                }
141155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
141255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
141355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
141455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1416b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1421466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1424409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleClose();
1425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
14261679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
14271679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
14281679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
1430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1431923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1432979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void saveWordInHistory(CharSequence result) {
1433979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mWord.size() <= 1) {
1434979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mWord.reset();
1435979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1436923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1437979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Skip if result is null. It happens in some edge case.
1438979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextUtils.isEmpty(result)) {
1439979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1440923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1441979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1442979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
1443979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final String resultCopy = result.toString();
1444979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        TypedWordAlternatives entry = new TypedWordAlternatives(resultCopy,
1445979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                new WordComposer(mWord));
1446979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.add(entry);
1447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1448923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14499fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isSuggestionsRequested() {
1450c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1451c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1453a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
14547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private boolean isShowingPunctuationList() {
14557e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        return mSuggestPuncList == mCandidateView.getSuggestions();
14567599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14577599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14589fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isShowingSuggestionsStrip() {
14597599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
14607599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
14617599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
14627599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14637599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCandidateStripVisible() {
14659fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isCorrecting())
14669fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14679fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
14689fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
14699fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
14709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14719fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1472923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1474409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
14755a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        mHandler.post(new Runnable() {
14765a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
14775a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            public void run() {
14785a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                if (DEBUG) {
14795a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    Log.d(TAG, "Switch to keyboard view.");
14805a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                }
14815a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                View v = mKeyboardSwitcher.getInputView();
14825a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                if (v != null) {
14835a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    // Confirms that the keyboard view doesn't have parent view.
14845a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    ViewParent p = v.getParent();
14855a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    if (p != null && p instanceof ViewGroup) {
14865a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                        ((ViewGroup) p).removeView(v);
14875a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    }
14885a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    setInputView(v);
14895a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                }
14905a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                setCandidatesViewShown(isCandidateStripVisible());
14915a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                updateInputViewShown();
14925a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
14935a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
14945a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        });
1495466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1496466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1497409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14987e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1499466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1500466741d8a78965b8509bf527344f289e50873092Mike LeBeau
15017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1502409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.getAndResetIsShowingHint()) {
1503466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1504466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1505466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1506466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
15077e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
15089ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
15099ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
15109ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
15119ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1512466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1513466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1514466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1515409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
15161679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(null);
15171b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
15199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1520409220583333bdf06290dd9fd42f91b5c0d1b11asatok                && !mVoiceConnector.isVoiceInputHighlighted()) {
1521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1523466741d8a78965b8509bf527344f289e50873092Mike LeBeau
15249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1525ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1528979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1529979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1530979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
15317e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords.Builder getTypedSuggestions(WordComposer word) {
15329ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka        return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null);
1533979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1534979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1535979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showCorrections(WordAlternatives alternatives) {
15361679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(null);
15377e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = alternatives.getAlternatives();
15387e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
15397e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), alternatives.getOriginalWord());
1540979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1541979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1542979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
1543979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // TODO Maybe need better way of retrieving previous word
1544e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1545979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mWordSeparators);
15467e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
15479ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
15491b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani        int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
15501679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
15511b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1552378a1b516d867671d292900c5d42aef3a0dc1556Ken Wakasa        boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
15536f7218627eda110a8454053f8ecb7b80edfdc8cesatok                && mSuggest.hasAutoCorrection();
1554a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1555923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If we're in basic correct
1556a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
1557979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                (preferCapitalization()
1558979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                        && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
1559979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1560979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1562923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15634a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1564979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1565979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !TextEntryState.isCorrecting();
1566979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1567a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1568a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1569f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1570f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1571f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1572f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1573f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1574a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
15759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
15769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
15779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
15789fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (previousSuggestions == mSuggestPuncList)
15799fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
15809fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
15819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
15827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1583979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
15844a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
15857e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
15867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
15877e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
158882411d47ba7e8133ed2390c6920945e139a738cesatok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords)) {
158982411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
159082411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
15917e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1592923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1593923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1596923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1597923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1598ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1600923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1601979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean pickDefaultSuggestion() {
1602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1603d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1604d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16076780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1608923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
1609923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
161055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
16119468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1612979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1613979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1614979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1616979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1619923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
16207e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
1621409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
16224f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1623979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final boolean correcting = TextEntryState.isCorrecting();
16249a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
16259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16269a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
16279a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
16281b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
16291b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
16301b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1631923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1632923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1633923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1634923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1635923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1636923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1637923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1638b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
16399a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16409a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16419a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1642923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16446a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
16456a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
1646979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0))
1647979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || isSuggestedPunctuation(suggestion.charAt(0)))) {
1648979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1649979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1650979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
16517e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
165255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1653a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1654a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1655a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
16569a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
16579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16589a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
16596a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
16606a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
16619a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
166255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
16639468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
16640c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1665979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1666979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1667979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToBigramDictionary(suggestion, 1);
16680c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1669979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
16707e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1671923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1673979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mAutoSpace && !correcting) {
1674923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendSpace();
16759a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1677979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1678b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        final boolean showingAddToDictionaryHint = index == 0 && mCorrectionMode > 0
1679b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion)
1680b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion.toString().toLowerCase());
1681b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1682979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!correcting) {
1683b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1684b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1685b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1686571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true);
1687ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1688b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        } else if (!showingAddToDictionaryHint) {
1689364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1690979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1691b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1692d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1693979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1694b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
169566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
169666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16979a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16989a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16999a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1701a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1702979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1703979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1704979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1705979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1706979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1707979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
170855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1709b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1710b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
17111679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1713923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1714409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.rememberReplacedWord(suggestion, mWordSeparators);
1715979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1716923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1717979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        saveWordInHistory(suggestion);
17189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mHasValidSuggestions = false;
1719923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1720b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.setPreferredLetters(null);
1721923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1723b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    /**
1724b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * Tries to apply any typed alternatives for the word if we have any cached alternatives,
1725b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * otherwise tries to find new corrections and completions for the word.
1726b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @param touching The word that the cursor is touching, with position information
1727b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @return true if an alternative was found, false otherwise.
1728b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     */
1729e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) {
1730b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // If we didn't find a match, search for result in typed word history
1731b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordComposer foundWord = null;
1732b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordAlternatives alternatives = null;
1733b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        for (WordAlternatives entry : mWordHistory) {
1734e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
1735b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                if (entry instanceof TypedWordAlternatives) {
1736b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    foundWord = ((TypedWordAlternatives) entry).word;
1737b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
1738b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                alternatives = entry;
1739b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                break;
1740b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1741b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
17421b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // If we didn't find a match, at least suggest corrections.
1743b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord == null
1744e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                && (mSuggest.isValidWord(touching.mWord)
1745e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
1746b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            foundWord = new WordComposer();
1747e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            for (int i = 0; i < touching.mWord.length(); i++) {
1748e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                foundWord.add(touching.mWord.charAt(i), new int[] {
1749e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    touching.mWord.charAt(i)
1750b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                });
1751b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1752e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
1753b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1754b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // Found a match, show suggestions
1755b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord != null || alternatives != null) {
1756b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (alternatives == null) {
1757e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                alternatives = new TypedWordAlternatives(touching.mWord, foundWord);
1758b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1759b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            showCorrections(alternatives);
1760b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (foundWord != null) {
1761b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord = new WordComposer(foundWord);
1762b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            } else {
1763b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord.reset();
1764b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1765b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return true;
1766b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1767b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return false;
1768b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
1769b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1770979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void setOldSuggestions() {
1771409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setShowingVoiceSuggestions(false);
1772b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
1773b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return;
1774b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1775979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        InputConnection ic = getCurrentInputConnection();
1776979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (ic == null) return;
17779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1778b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Extract the selected or touching text
1779e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
1780b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    mLastSelectionStart, mLastSelectionEnd, mWordSeparators);
1781979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1782e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (touching != null && touching.mWord.length() > 1) {
1783b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.beginBatchEdit();
1784979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1785409220583333bdf06290dd9fd42f91b5c0d1b11asatok                if (!mVoiceConnector.applyVoiceAlternatives(touching)
1786409220583333bdf06290dd9fd42f91b5c0d1b11asatok                        && !applyTypedAlternatives(touching)) {
1787b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    abortCorrection(true);
1788b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                } else {
1789979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    TextEntryState.selectedForCorrection();
1790e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    EditingUtils.underlineWord(ic, touching);
1791979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
1792b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1793b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.endBatchEdit();
1794979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } else {
1795979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                abortCorrection(true);
1796ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                setPunctuationSuggestions();  // Show the punctuation suggestions list
1797979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1798979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1799979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            abortCorrection(true);
1800979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1801979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1802979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1803ca26f20fa4903de46e374babbfba8c8a1a5cac93satok    private void setPunctuationSuggestions() {
18047e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(mSuggestPuncList);
18059fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
18066a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
18076a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1808979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToDictionaries(CharSequence suggestion, int frequencyDelta) {
1809979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1810979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1811979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1812979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1813979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1814979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1815979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1816979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1817979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1818979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param addToBigramDictionary true if it should be added to bigram dictionary if possible
1819979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1820979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1821979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            boolean addToBigramDictionary) {
1822979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
18230c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
18240c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
18250c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1826979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1827979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1828979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1829979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1830e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
1831e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || (!mSuggest.isValidWord(suggestion.toString())
1832e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
1833e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1834e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1835979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1836e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1837e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1838e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    mSentenceSeparators);
1839e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1840e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1841979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
184232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
184332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
184432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
1845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCursorTouchingWord() {
1846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1849923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
185155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toLeft.charAt(0))
185255b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toLeft.charAt(0))) {
1853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1855a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
185655b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toRight.charAt(0))
185755b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toRight.charAt(0))) {
1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1860923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1862a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1863dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1864dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1865dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1866dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1867dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1869923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
18709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions && length > 0) {
1871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1872c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = true;
1873504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1876504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1877504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
1878923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1879923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
188130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
188230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
188330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
188430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
188530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1886504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1887504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
188830be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
188930be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                TextEntryState.typedCharacter(punctuation.charAt(0), true);
189030be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
189130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1892504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
189330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mHasValidSuggestions = true;
1894504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1895504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1896504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1897d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1898923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1899923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1900c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1901923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1902923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1903923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1904923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1905923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1906923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1907a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1908923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
1909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
1910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
1911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1912923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1913979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSentenceSeparator(int code) {
1914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mSentenceSeparators.contains(String.valueOf((char)code));
1915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1916923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1917923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void sendSpace() {
1918571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
1919b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
19230b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1926c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
1927c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1928c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
19294ab730dbd34fad323063f2ffd31ce33de746668dsatok        toggleLanguage(true, true);
19304ab730dbd34fad323063f2ffd31ce33de746668dsatok    }
19314ab730dbd34fad323063f2ffd31ce33de746668dsatok
19324ab730dbd34fad323063f2ffd31ce33de746668dsatok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
19333f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani    private void toggleLanguage(boolean reset, boolean next) {
1934de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
19354ab730dbd34fad323063f2ffd31ce33de746668dsatok            mSubtypeSwitcher.toggleLanguage(reset, next);
19364ab730dbd34fad323063f2ffd31ce33de746668dsatok        }
19374ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1938b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19398b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final EditorInfo attribute = getCurrentInputEditorInfo();
1940c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int mode = initializeInputAttributesAndGetMode((attribute != null)
1941c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                ? attribute.inputType : 0);
1942d98c20b036ff02f99406dabb8cc4fdf4a51cd6c4Tadashi G. Takaoka        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
1943409220583333bdf06290dd9fd42f91b5c0d1b11asatok        switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
1944409220583333bdf06290dd9fd42f91b5c0d1b11asatok                mVoiceConnector.isVoiceButtonOnPrimary());
19450ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
1946b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
194736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
194836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
19495a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
195036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
195136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            String key) {
19520ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
19539502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
195436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = true;
19559502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) {
19569502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            mReCorrectionEnabled = sharedPreferences.getBoolean(
19579502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                    Settings.PREF_RECORRECTION_ENABLED,
1958458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                    mResources.getBoolean(R.bool.default_recorrection_enabled));
195936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
196036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
196136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
19625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
19638aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
1964363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        if (mConfigSwipeDownDismissKeyboardEnabled)
1965363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onPress(int primaryCode) {
1970cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1971cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1972cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1973cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
19741679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19751679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1976571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1977b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.onPressShift();
1978e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19796c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
198040a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
19816c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1982681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19855a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1986923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onRelease(int primaryCode) {
19871679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19883f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
19891679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        switcher.keyReleased();
19901679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1991571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1992889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka            switcher.onReleaseShift();
1993e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19946c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
199540a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1997a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1998a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // receive ringer mode changes to detect silent mode
2000923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
2001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
2002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2003923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateRingerMode();
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);
21259502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON,
21269b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                mResources.getBoolean(R.bool.config_default_popup_preview));
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
217789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    private boolean isQuickFixesEnabled(SharedPreferences sp) {
217889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showQuickFixesOption = mResources.getBoolean(
217989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_quick_fixes_option);
218089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showQuickFixesOption) {
218189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
218289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
218389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_QUICK_FIXES, mResources.getBoolean(
218489764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_quick_fixes));
218589764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard    }
218689764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard
2187b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
21881b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
21891b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
21909ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
21911b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String autoCorrectionOff = mResources.getString(
21929ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.string.auto_correction_threshold_mode_index_off);
21931b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
2194b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2195b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2196b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
219789764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        final boolean showBigramSuggestionsOption = mResources.getBoolean(
219889764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_enable_bigram_suggestions_option);
219989764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        if (!showBigramSuggestionsOption) {
220089764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard            return isAutoCorrectEnabled(sp);
220189764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        }
220289764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, mResources.getBoolean(
220389764ad4ac5415fb9753c38671b1fa18b9cdd390Jean Chalard                R.bool.config_default_bigram_suggestions));
2204b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2205b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
22066a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
22077e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (mSuggestPuncs != null || mSuggestPuncList != null)
22087e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            return;
22097e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = new SuggestedWords.Builder();
22107e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        String puncs = mResources.getString(R.string.suggested_punctuations);
22117e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (puncs != null) {
22127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            for (int i = 0; i < puncs.length(); i++) {
22137e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                builder.addWord(puncs.subSequence(i, i + 1));
22146a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
22156a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
22167e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncList = builder.build();
22177e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncs = puncs;
22186a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
22196a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSuggestedPunctuation(int code) {
2221979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestPuncs.contains(String.valueOf((char)code));
2222979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2223979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
22242fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
222585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
222685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
222785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
222885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
222985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
223085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
223185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22322fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
22332fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
22342fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
22352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
223685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
22372fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    launchSettings();
22382fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
223985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
22402fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    Intent intent = new Intent(
22412fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            android.provider.Settings.ACTION_INPUT_METHOD_SUBTYPE_SETTINGS);
22422fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
22432fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
22442fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
22452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    intent.putExtra(android.provider.Settings.EXTRA_INPUT_METHOD_ID,
22462fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            mInputMethodId);
22472fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
22482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
22492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
22502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
225185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
225285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
22532fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22552fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
225685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
225785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
225885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
225985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
226085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
226185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2263923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2265923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
226685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
22672fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    launchSettings();
22682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
226985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
22702fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    mImm.showInputMethodPicker();
22712fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
227485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
227585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        showOptionsMenuInternal(title, items, listener);
22762fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
22772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka
227885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka    private void showOptionsMenuInternal(CharSequence title, CharSequence[] items,
227985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka            DialogInterface.OnClickListener listener) {
22802fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        AlertDialog.Builder builder = new AlertDialog.Builder(this);
22812fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setCancelable(true);
22822fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setIcon(R.drawable.ic_dialog_keyboard);
22832fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka        builder.setNegativeButton(android.R.string.cancel, null);
228485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setItems(items, listener);
228585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        builder.setTitle(title);
2286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2287a2ad96d95986eb61c3d2d5abce154fb4c3803cacTadashi G. Takaoka        mOptionsDialog.setCanceledOnTouchOutside(true);
2288923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
2290979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
2291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22977e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
22987e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2299923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2300a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2303923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
23059fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
23079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mHasValidSuggestions=" + mHasValidSuggestions);
2308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
2309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoSpace=" + mAutoSpace);
23101b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
2312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
2313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
2314979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        p.println("  mPopupOn=" + mPopupOn);
2315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
23166e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2317923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2318a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2323a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2328923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
233434386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
23350ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    @Override
23360ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
23374ab730dbd34fad323063f2ffd31ce33de746668dsatok        SubtypeSwitcher.getInstance().updateSubtype(subtype);
23380ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
2339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2340