LatinIME.java revision bbd651a00898dabf6b2ae0e715d99953ea81063f
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;
70e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.HorizontalScrollView;
7140ac45ebdcd71940394dda00371d4847f7db0f26Ken Wakasaimport android.widget.LinearLayout;
72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
73466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
74466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
75466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.ArrayList;
76b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimodaimport java.util.Arrays;
77466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
78466741d8a78965b8509bf527344f289e50873092Mike LeBeau
79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
8255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokapublic class LatinIME extends InputMethodService implements KeyboardActionListener,
83e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        SharedPreferences.OnSharedPreferenceChangeListener {
84466741d8a78965b8509bf527344f289e50873092Mike LeBeau    private static final String TAG = "LatinIME";
85979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
86409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean DEBUG = false;
87409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
88a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
89fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_SUGGESTIONS = 180;
90fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa    private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
91d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    private static final int DELAY_UPDATE_SHIFT_STATE = 300;
92fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
96d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
97a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Contextual menu positions
99c1ff28462eee5880267fd2eae4da389b25f6f3daKen Wakasa    private static final int POS_METHOD = 0;
100c1ff28462eee5880267fd2eae4da389b25f6f3daKen Wakasa    private static final int POS_SETTINGS = 1;
101466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1027599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1037599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1047599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1057599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1067599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1077599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1087599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1097599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1107599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1117599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1127599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1137599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1147599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1157599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
116e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1191b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
120a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AlertDialog mOptionsDialog;
122a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12379efbed76f638be298493107fa2d0cd1b5eb529esatok    private InputMethodManager mImm;
12471c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1250ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
126409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private VoiceIMEConnector mVoiceConnector;
127a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
129979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
1302bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer    private ContactsDictionary mContactsDictionary;
1314ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani    private AutoDictionary mAutoDictionary;
13236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1337e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    private Resources mResources;
13427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    private SharedPreferences mPrefs;
13536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
136c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
137c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mAutoSpace;
138c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
139c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
140c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
141c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
14271c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final StringBuilder mComposing = new StringBuilder();
143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private WordComposer mWord = new WordComposer();
144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
1459fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean mHasValidSuggestions;
146e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mHasDictionary;
1479a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private boolean mJustAddedAutoSpace;
148e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private boolean mAutoCorrectEnabled;
14966b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok    private boolean mReCorrectionEnabled;
150979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mBigramSuggestionEnabled;
151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCorrectOn;
152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mVibrateOn;
153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSoundOn;
154979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mPopupOn;
155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mAutoCap;
1566e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani    private boolean mQuickFixes;
157363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka    private boolean mConfigSwipeDownDismissKeyboardEnabled;
158de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDelayBeforeFadeoutLanguageOnSpacebar;
159de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka    private int mConfigDurationOfFadeoutLanguageOnSpacebar;
160d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka    private float mConfigFinalFadeoutFactorOfLanguageOnSpacebar;
161409220583333bdf06290dd9fd42f91b5c0d1b11asatok
16279efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
16379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
16479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mOrientation;
165979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
16679efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
16779efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
1687e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestPuncList;
169979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Indicates whether the suggestion strip is to be on in landscape
171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mJustAccepted;
172c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa    private boolean mJustReverted;
173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
175a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
1772296317b8f0209789f797ac8a2fcb70e03f6d001Eric Laurent    // Align sound effect volume on music volume
17871c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private static final float FX_VOLUME = -1.0f;
179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mSilentMode;
180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
181979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /* package */ String mWordSeparators;
182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private String mSentenceSeparators;
183979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private String mSuggestPuncs;
184409220583333bdf06290dd9fd42f91b5c0d1b11asatok    // TODO: Move this flag to VoiceIMEConnector
18581c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
186466741d8a78965b8509bf527344f289e50873092Mike LeBeau
187dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
188dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
189979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean mRefreshKeyboardRequired;
190dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
19171c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
192979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
193979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public abstract static class WordAlternatives {
194979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        protected CharSequence mChosenWord;
1954f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
196979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives() {
197979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
198979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
199979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
200979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public WordAlternatives(CharSequence chosenWord) {
201979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mChosenWord = chosenWord;
202979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
203979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
204979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
205979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public int hashCode() {
206979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord.hashCode();
207979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
208979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
209979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public abstract CharSequence getOriginalWord();
210979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
211979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getChosenWord() {
212979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return mChosenWord;
213979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
214979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public abstract SuggestedWords.Builder getAlternatives();
216979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
217979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
218979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public class TypedWordAlternatives extends WordAlternatives {
219979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        private WordComposer word;
220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
221979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives() {
222979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Nothing
223979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
224979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
225979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public TypedWordAlternatives(CharSequence chosenWord, WordComposer wordComposer) {
226979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            super(chosenWord);
227979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            word = wordComposer;
228979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
230979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
231979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        public CharSequence getOriginalWord() {
232979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return word.getTypedWord();
233979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
234979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
235979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        @Override
2367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        public SuggestedWords.Builder getAlternatives() {
237979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return getTypedSuggestions(word);
238979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
239979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
24036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
241571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka    public final UIHandler mHandler = new UIHandler();
242d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
243409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public class UIHandler extends Handler {
244d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
245d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
247d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
248de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
249de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
250d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
253de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final KeyboardSwitcher switcher = mKeyboardSwitcher;
254de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getInputView();
255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
256d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
257d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                updateSuggestions();
258d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
259d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
260d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                setOldSuggestions();
261d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
262d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
263de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
264d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
265d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
266e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mVoiceConnector.handleVoiceResults(preferCapitalization()
267de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
268de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
269de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
270de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
27166432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
272d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            (1.0f + mConfigFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
27366432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
274de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
275de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        mConfigDurationOfFadeoutLanguageOnSpacebar);
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
277de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
278de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (inputView != null)
27966432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
280d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            mConfigFinalFadeoutFactorOfLanguageOnSpacebar, (LatinKeyboard)msg.obj);
281d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
285d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
286d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), DELAY_UPDATE_SUGGESTIONS);
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
290d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
291d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
292d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
294d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
295d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
296d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
297d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
298d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
299d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
300d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                    DELAY_UPDATE_OLD_SUGGESTIONS);
302d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
303d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
304d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
306d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
309d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), DELAY_UPDATE_SHIFT_STATE);
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
320de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
321d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
322de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
323de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
324de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            final LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
325de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
326de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                final LatinKeyboard keyboard = inputView.getLatinKeyboard();
327de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
328de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                if (mConfigDelayBeforeFadeoutLanguageOnSpacebar != 0)
329d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(localeChanged ? 1.0f
330d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                            : mConfigFinalFadeoutFactorOfLanguageOnSpacebar, keyboard);
331de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is always displayed when the delay is negative.
332d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka                if (localeChanged && mConfigDelayBeforeFadeoutLanguageOnSpacebar > 0) {
333de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
334de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                            mConfigDelayBeforeFadeoutLanguageOnSpacebar);
335de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
336de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
337de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
338d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3407e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
3417e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
34227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
34327d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
34427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
34527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.init(this, prefs);
34627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
347363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
349363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
35079efbed76f638be298493107fa2d0cd1b5eb529esatok        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
3510ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
3520ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
353363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
354363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
355363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
3569502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mReCorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
357363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                res.getBoolean(R.bool.default_recorrection_enabled));
358363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mConfigSwipeDownDismissKeyboardEnabled = res.getBoolean(
359363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka                R.bool.config_swipe_down_dismiss_keyboard_enabled);
360de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDelayBeforeFadeoutLanguageOnSpacebar = res.getInteger(
361de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_delay_before_fadeout_language_on_spacebar);
362de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        mConfigDurationOfFadeoutLanguageOnSpacebar = res.getInteger(
363de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                R.integer.config_duration_of_fadeout_language_on_spacebar);
364d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        mConfigFinalFadeoutFactorOfLanguageOnSpacebar = res.getInteger(
36566432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                R.integer.config_final_fadeout_percentage_of_language_on_spacebar) / 100.0f;
366979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3679502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
368979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
3699502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
370979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
3710ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
372979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
373979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
3749502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
375979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
376979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
377979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
378363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mOrientation = res.getConfiguration().orientation;
3796a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        initSuggestPuncList();
380b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // register to receive ringer mode changes for silent mode
382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
383923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
38427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
3853f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        prefs.registerOnSharedPreferenceChangeListener(this);
386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
38736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
388979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
389458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa     * Returns a main dictionary resource id
390458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa     * @return main dictionary resource id
391979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
392458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa    public static int getMainDictionaryResourceId(Resources res) {
393458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final String MAIN_DIC_NAME = "main";
394979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        String packageName = LatinIME.class.getPackage().getName();
395458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName);
396979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
397979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3980ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
3990ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
4004ab730dbd34fad323063f2ffd31ce33de746668dsatok        String locale = mSubtypeSwitcher.getInputLocaleStr();
40136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4020ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
40336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
40436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
40536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
40627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
4079502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
408979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
409458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
410458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        int mainDicResId = getMainDictionaryResourceId(res);
411458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSuggest = new Suggest(this, mainDicResId);
4121b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
413e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
4140ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mUserDictionary = new UserDictionary(this, locale);
415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
416e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
417e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
4182bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer        mSuggest.setContactsDictionary(mContactsDictionary);
419e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
420e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
42134386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mSuggest.setAutoDictionary(mAutoDictionary);
422e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
423e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
424e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
425e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
426e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
427458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mWordSeparators = res.getString(R.string.word_separators);
428458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        mSentenceSeparators = res.getString(R.string.sentence_separators);
42936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
4300ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.changeSystemLocale(savedLocale);
431923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
43236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
433466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
434466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
435e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
436e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
437e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
438979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
439923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
440409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.destroy();
441979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
442979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
443923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
444923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
445923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
446923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
448dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
449b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
450b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        if (conf.orientation != mOrientation) {
451466741d8a78965b8509bf527344f289e50873092Mike LeBeau            InputConnection ic = getCurrentInputConnection();
452466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
453466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
454b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mOrientation = conf.orientation;
455b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
4568b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
45781c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
459bbd651a00898dabf6b2ae0e715d99953ea81063fLuca Zanolin        mVoiceConnector.onConfigurationChanged(conf);
46081c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
462b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
4658d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
466923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
468923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
469923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateCandidatesView() {
470e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = getLayoutInflater();
471e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LinearLayout container = (LinearLayout)inflater.inflate(R.layout.candidates, null);
472e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateViewContainer = container;
473e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (container.getPaddingRight() != 0) {
474e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            HorizontalScrollView scrollView =
475e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                    (HorizontalScrollView) container.findViewById(R.id.candidates_scroll_view);
476e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
477e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            container.setGravity(Gravity.CENTER_HORIZONTAL);
478e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
479e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mCandidateView = (CandidateView) container.findViewById(R.id.candidates);
480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCandidateView.setService(this);
481923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setCandidatesViewShown(true);
482e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return container;
483923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
48547f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    private static boolean isPasswordVariation(int variation) {
486e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
487e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
488e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
48947f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    }
49047f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins
49147f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    private static boolean isEmailVariation(int variation) {
492e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
493e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
49447f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins    }
49547f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins
496a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
49845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
49945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getInputView();
5008e09172df1bb176cc899940862c56bed9b9aec4esatok
501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
502979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5068d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
5074ab730dbd34fad323063f2ffd31ce33de746668dsatok
50836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mRefreshKeyboardRequired) {
50936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = false;
510c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            onRefreshKeyboard();
51136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
51236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.newSession(this);
5146c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
515c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
516c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
517c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // want to enable the voice button.
518c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.resetVoiceStates(isPasswordVariation(
519c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                attribute.inputType & InputType.TYPE_MASK_VARIATION));
520c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
521c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
522c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
523c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
524c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
525c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mComposing.setLength(0);
526c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHasValidSuggestions = false;
527c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
528c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mJustAddedAutoSpace = false;
529c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
530c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        loadSettings(attribute);
531c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
532c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.loadKeyboard(mode, attribute.imeOptions,
533c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonEnabled(),
534c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    mVoiceConnector.isVoiceButtonOnPrimary());
535c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka            switcher.updateShiftState();
536c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
537c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
538c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        setCandidatesViewShownInternal(isCandidateStripVisible(),
539c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                false /* needsInputViewShown */ );
540c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
541c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
542c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
543c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        updateCorrectionMode();
544c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
545c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setPreviewEnabled(mPopupOn);
546c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
547c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
548c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        checkReCorrectionOnStart();
549c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setForeground(true);
550c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
551c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mVoiceConnector.onStartInputView(inputView.getWindowToken());
552c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
553c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
554c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
555c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
556c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private int initializeInputAttributesAndGetMode(int inputType) {
557c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
558c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mAutoSpace = false;
559e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
5609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
5611b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
5621b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
563dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
564f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka        final int mode;
565c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        switch (inputType & InputType.TYPE_MASK_CLASS) {
566e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_NUMBER:
567e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_DATETIME:
5685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_NUMBER;
5692c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                break;
570e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_PHONE:
5715a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_PHONE;
572923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
573e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case InputType.TYPE_CLASS_TEXT:
5749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = true;
575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Make sure that passwords are not displayed in candidate view
57647f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isPasswordVariation(variation)) {
5779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
57947f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isEmailVariation(variation)
580e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
581923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = false;
582923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
583923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mAutoSpace = true;
584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
58547f795dc8709f95b35888fbcca80c0c18dbe63edLeon Scroggins                if (isEmailVariation(variation)) {
5869fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
5875a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_EMAIL;
588e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
5899fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
5905a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_URL;
591e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
5925a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_IM;
593e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
5949fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
5955a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_TEXT;
596e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
5975a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_WEB;
5986c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // If it's a browser edit field and auto correct is not ON explicitly, then
5996c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    // disable auto correction, but keep suggestions on.
600c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                    if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
601e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                        mInputTypeNoAutoCorrect = true;
6026c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani                    }
603f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka                } else {
6045a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    mode = KeyboardId.MODE_TEXT;
605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
60636ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani
60736ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If NO_SUGGESTIONS is set, don't do prediction.
608c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
6099fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
610e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
61136ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
61236ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                // If it's not multiline and the autoCorrect flag is not set, then don't correct
613c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0 &&
614c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                        (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
615e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
61636ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
617c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
6189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mIsSettingsSuggestionStripOn = false;
6191b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    mApplicationSpecifiedCompletionOn = isFullscreenMode();
620923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            default:
6235a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mode = KeyboardId.MODE_TEXT;
624f8e30a91537b8b4920887d0d4f0771de3a23c4cbTadashi G. Takaoka                break;
625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
626c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mode;
627923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
628923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
629b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    private void checkReCorrectionOnStart() {
630d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (!mReCorrectionEnabled) return;
631d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
632d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
633d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (ic == null) return;
634d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        // There could be a pending composing span.  Clean it up first.
635d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        ic.finishComposingText();
636d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa
6379fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isShowingSuggestionsStrip() && isSuggestionsRequested()) {
638b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // First get the cursor position. This is required by setOldSuggestions(), so that
639b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // it can pass the correct range to setComposingRegion(). At this point, we don't
6404ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka            // have valid values for mLastSelectionStart/End because onUpdateSelection() has
641b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // not been called yet.
642b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedTextRequest etr = new ExtractedTextRequest();
643b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            etr.token = 0; // anything is fine here
644b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            ExtractedText et = ic.getExtractedText(etr, 0);
645b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            if (et == null) return;
646b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
647b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionStart = et.startOffset + et.selectionStart;
648b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            mLastSelectionEnd = et.startOffset + et.selectionEnd;
649b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
650b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani            // Then look for possible corrections in a delayed fashion
65155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) {
652d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateOldSuggestions();
65355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            }
654b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani        }
655b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani    }
656b8fa10080dfac777fce7c8a7fc3180e8b540f9f5Amith Yamasani
657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
659923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
660a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
661979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
6621b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
663979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
664409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
665409220583333bdf06290dd9fd42f91b5c0d1b11asatok
6665a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
667d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
6684ff60be170872503cca0275ef3488b7379b5311bAmith Yamasani        if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
669979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
670466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
671466741d8a78965b8509bf527344f289e50873092Mike LeBeau
672466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
6736495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
6746495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
6755a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getInputView();
676d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.setForeground(false);
677d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
678d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
679d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
6806495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
6816495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
6826495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
683466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
684466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
685409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.showPunctuationHintIfNecessary();
686923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
687923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
688923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
689923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
690923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
691923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
693923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
694466741d8a78965b8509bf527344f289e50873092Mike LeBeau
695466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
696466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
697466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
698466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
699466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
700466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
701466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
702466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
703466741d8a78965b8509bf527344f289e50873092Mike LeBeau
704409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setCursorAndSelection(newSelEnd, newSelStart);
7054f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
7089fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((((mComposing.length() > 0 && mHasValidSuggestions)
7098e09172df1bb176cc899940862c56bed9b9aec4esatok                || mVoiceConnector.isVoiceInputHighlighted()) && (newSelStart != candidatesEnd
7108e09172df1bb176cc899940862c56bed9b9aec4esatok                        || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart)) {
711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mComposing.setLength(0);
7129fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
713d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
714923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
715923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
716923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
717923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
718923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
719409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.setVoiceInputHighlighted(false);
7209fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (!mHasValidSuggestions && !mJustAccepted) {
7219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            switch (TextEntryState.getState()) {
722e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case ACCEPTED_DEFAULT:
723e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                TextEntryState.reset();
724e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                // $FALL-THROUGH$
725e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            case SPACE_AFTER_PICKED:
726e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mJustAddedAutoSpace = false; // The user moved the cursor.
727e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
728e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            default:
729e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                break;
7309a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
731923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
732923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mJustAccepted = false;
733d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
734466741d8a78965b8509bf527344f289e50873092Mike LeBeau
735979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
736979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
737979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
738466741d8a78965b8509bf527344f289e50873092Mike LeBeau
7399fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isShowingSuggestionsStrip()) {
74066b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok            // Don't look for corrections if the keyboard is not visible
7411679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()) {
74266b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                // Check if we should go in or out of correction mode.
7439fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                if (isSuggestionsRequested() && !mJustReverted
74466b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
74566b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                                || TextEntryState.isCorrecting())
7469fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                                && (newSelStart < newSelEnd - 1 || !mHasValidSuggestions)) {
74766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
748d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                        mHandler.postUpdateOldSuggestions();
74966b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    } else {
75066b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                        abortCorrection(false);
75155b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        // Show the punctuation suggestions list if the current one is not
752364da8c618303a7764595d2c15ee034a7671365dKen Wakasa                        // and if not showing "Touch again to save".
7537599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        if (mCandidateView != null && !isShowingPunctuationList()
7547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                                && !mCandidateView.isShowingAddToDictionaryHint()) {
755ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                            setPunctuationSuggestions();
75655b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                        }
75766b42a1c2d38813be104a7f0435ec6e6ec1c6e65satok                    }
758b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
759466741d8a78965b8509bf527344f289e50873092Mike LeBeau            }
760466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
763c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
764c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
765c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
766c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
767c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
768c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
769c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
770c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
771c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
772c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
7739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
774c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
775c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
776c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
777c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
778c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
779c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
780c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
781c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
782c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
783c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
784c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
785c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
786c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
787c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
788c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
7899fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mReCorrectionEnabled && isSuggestionsRequested()) return;
790c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
791c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
792c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
793c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
794923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
795923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
796979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
7971b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mKeyboardSwitcher.onAutoCorrectionStateChanged(false);
798979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
799923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
8006e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
8016e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
8026e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
8036e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
804409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.hideVoiceWindow(mConfigurationChanging);
805979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.clear();
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
808923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
810923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
8111b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
812979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
813a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
8141b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int count = (applicationSpecifiedCompletions != null)
8151b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    ? applicationSpecifiedCompletions.length : 0;
8161b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            for (int i = 0; i < count; i++) {
817a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
819923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8201b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
8211b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
8221b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
823b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
824923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
826a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
8277e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
8281b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
8297e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setTypedWordValid(true)
8307e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    .setHasMinimalSuggestion(true);
831979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
8327e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
833923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
834543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa            setCandidatesViewShown(true);
835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
836923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
838543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // TODO: Remove this if we support candidates with hard keyboard
840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (onEvaluateInputViewShown()) {
8411679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            super.setCandidatesViewShown(shown
8421679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true));
843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
845a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
847543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    public void setCandidatesViewShown(boolean shown) {
848543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa        setCandidatesViewShownInternal(shown, true /* needsInputViewShown */ );
849543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
850543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
851543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
854264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        if (!isFullscreenMode()) {
855264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project            outInsets.contentTopInsets = outInsets.visibleTopInsets;
856264b19a6853ab3d13d26270e99a13dc015b01bebThe Android Open Source Project        }
857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
858a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
860979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
861458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
862458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
863979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
864979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
865458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
866979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
867979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
868979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
869979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
870979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
871979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
872979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
873979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
876e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
877e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
878e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (mKeyboardSwitcher.getInputView().handleBack()) {
8796e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
8806e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
881e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
882e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
883923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
884923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
885923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
887923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
888923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
889923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
890e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
891e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
892e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
893e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
894e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
895e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
896e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
897e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
898e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
899e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
900e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
901e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                InputConnection ic = getCurrentInputConnection();
902e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
903e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
904e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
905e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
906e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
907923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
908923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
911409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void commitTyped(InputConnection inputConnection) {
9129fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
9139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHasValidSuggestions = false;
914923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mComposing.length() > 0) {
915923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (inputConnection != null) {
916923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    inputConnection.commitText(mComposing, 1);
917923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
918923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCommittedLength = mComposing.length();
919923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedTyped(mComposing);
920979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
921923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
922923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
923923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
924923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
926b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
927923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
9281c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
929e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) {
930b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
9311c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
932b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
9331c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
9341c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void swapPunctuationAndSpace() {
936923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
940571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastTwo.charAt(0) == Keyboard.CODE_SPACE
941571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && isSentenceSeparator(lastTwo.charAt(1))) {
942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
943923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
946b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9479a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
9501c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
9514ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    private void reswapPeriodAndSpace() {
9524ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        final InputConnection ic = getCurrentInputConnection();
9534ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (ic == null) return;
9544ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
9554ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastThree != null && lastThree.length() == 3
956571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(0) == Keyboard.CODE_PERIOD
957571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
958571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_PERIOD) {
9594ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.beginBatchEdit();
9604ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.deleteSurroundingText(3, 0);
9614ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.commitText(" ..", 1);
9624ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            ic.endBatchEdit();
963b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9644ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
9654ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
9664ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void doubleSpace() {
968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        //if (!mAutoPunctuate) return;
969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
972923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                && Character.isLetterOrDigit(lastThree.charAt(0))
975571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
976571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
981b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
9829a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
985a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
98641a519729505a877844f2c57a33509c302dddbceKen Wakasa    private void maybeRemovePreviousPeriod(CharSequence text) {
98741a519729505a877844f2c57a33509c302dddbceKen Wakasa        final InputConnection ic = getCurrentInputConnection();
98841a519729505a877844f2c57a33509c302dddbceKen Wakasa        if (ic == null) return;
98941a519729505a877844f2c57a33509c302dddbceKen Wakasa
99041a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
99141a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
99241a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
9934ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
994571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
995571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
99641a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
99741a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
99841a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
99941a519729505a877844f2c57a33509c302dddbceKen Wakasa
10009a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
10019a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
10029a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
10039a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
10049a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
10059a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1006571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
10079a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
10089a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
10099a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
10109a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
10136558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
10146558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1015d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1017923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1019923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1020923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1021923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1022923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1023923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1026a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1027e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
10289a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10299502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
10309a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                showOptionsMenu();
10319a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10329a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10339a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10349a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10359a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10369a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1037e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyLongPressed() {
10389a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        if (!isShowingOptionDialog()) {
10399502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
104079efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
10419a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            } else {
10429a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok                launchSettings();
10439a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
10449a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
10459a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10469a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10479a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
10489a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
10499a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
10509a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
10515f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
10525a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
10538aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1054923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1055571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1059b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1060b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1061923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1062571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
10634189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            handleBackspace();
10644189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
10654189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
10664189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1067571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
10684189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
10694189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!distinctMultiTouch)
1070b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
10714189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1072e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
10734189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
10744189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!distinctMultiTouch)
1075b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
10764189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1077571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
10784189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
10794189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
10804189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
10814189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1082e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1083e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
10844189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1085e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS_LONGPRESS:
1086e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyLongPressed();
10874189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1088571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_NEXT_LANGUAGE:
10894189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, true);
10904189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1091571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_PREV_LANGUAGE:
10924189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            toggleLanguage(false, false);
10934189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1094571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1095b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
10964189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
109720cdb37bd062ae6cb6d42ad6229a19733476cd55satok        case Keyboard.CODE_VOICE:
109820cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
10994189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1100571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
110145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
11024189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
11034189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
1104571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (primaryCode != Keyboard.CODE_ENTER) {
11054189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                mJustAddedAutoSpace = false;
11064189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11074189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            RingCharBuffer.getInstance().push((char)primaryCode, x, y);
11084189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnInputChar();
11094189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (isWordSeparator(primaryCode)) {
11104189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleSeparator(primaryCode);
11114189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
11124189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleCharacter(primaryCode, keyCodes);
11134189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
11144189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Cancel the just reverted state
1115c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1117b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1118dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1119dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1121a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11238aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1124409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.commitVoiceInput();
1125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1127979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        abortCorrection(false);
1128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
112955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
113041a519729505a877844f2c57a33509c302dddbceKen Wakasa        maybeRemovePreviousPeriod(text);
1131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1133b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
11345f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
1135c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
11369a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAddedAutoSpace = false;
1137dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11405a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
11418aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
114283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
11435f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
114483e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
114583e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleBackspace() {
1147409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.logAndRevertVoiceInput()) return;
11484f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1149504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1150504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1151979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1152979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1153409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleBackspace();
11544f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1155504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        boolean deleteChar = false;
11569fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int length = mComposing.length();
1158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
1159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.delete(length - 1, length);
1160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.deleteLast();
1161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mComposing.length() == 0) {
11639fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                    mHasValidSuggestions = false;
1164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1165d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
1166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            deleteChar = true;
1171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1172d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1173504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1175979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
1176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            revertLastWord(deleteChar);
1177979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1179504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1180504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1181504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1182dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
11846558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
11856558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
118655b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
11876558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
11886558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
11896558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
11906558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
11916558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
11926558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                revertLastWord(deleteChar);
11936558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
11956558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
11966558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
11976558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1199923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1200c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa        mJustReverted = false;
1201979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
120445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
120545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
120645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int navigationFlags =
120745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
120845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & navigationFlags) == 0) {
120945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
121045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
121145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
121245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
121345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
121445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
121545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
121645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
121745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
121845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
121945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
122045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
122145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
122245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
122345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
122445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
122545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
122645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
122745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
1228979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void abortCorrection(boolean force) {
1229979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (force || TextEntryState.isCorrecting()) {
1230ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            TextEntryState.onAbortCorrection();
1231ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setCandidatesViewShown(isCandidateStripVisible());
1232979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            getCurrentInputConnection().finishComposingText();
1233b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1234923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1236a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleCharacter(int primaryCode, int[] keyCodes) {
1238409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleCharacter();
12394f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1240b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) {
1241b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            abortCorrection(false);
1242b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
12434f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1244e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
12459fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (isAlphabet(code) && isSuggestionsRequested() && !isCursorTouchingWord()) {
12469fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (!mHasValidSuggestions) {
12479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                mHasValidSuggestions = true;
1248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mComposing.setLength(0);
1249979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                saveWordInHistory(mBestWord);
1250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWord.reset();
1251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
12531679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1254f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1255eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1256eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1257eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1258eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1259e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1260e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
1261e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                int upperCaseCode = Character.toUpperCase(code);
1262e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (upperCaseCode != code) {
1263e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    code = upperCaseCode;
126412a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
126512a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
1266e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    String upperCase = new String(new int[] {code}, 0, 1).toUpperCase();
12678aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka                    onTextInput(upperCase);
126812a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
126912a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1270979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
12729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1273f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (mComposing.length() == 0 && switcher.isAlphabetMode()
1274f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
12750b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa                mWord.setFirstCharCapitalized(true);
1276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1277e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mComposing.append((char) code);
1278e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mWord.add(code, keyCodes);
1279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            InputConnection ic = getCurrentInputConnection();
1280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
12811c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
12821c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                if (mWord.size() == 1) {
1283b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
12841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.setComposingText(mComposing, 1);
1286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1287d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1288923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1289e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1291b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1292979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
1293e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        TextEntryState.typedCharacter((char) code, isWordSeparator(code));
1294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleSeparator(int primaryCode) {
1297409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleSeparator();
12984f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
129955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
13006558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
13026558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
13036558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
13061b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1309979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            abortCorrection(false);
1310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
13119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mHasValidSuggestions) {
1312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1313a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1316c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            if (mAutoCorrectOn && primaryCode != '\'' && !mJustReverted) {
1317979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                pickedDefault = pickDefaultSuggestion();
13189a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // Picked the suggestion by the space key.  We consider this
13199a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                // as "added an auto space".
1320571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                if (primaryCode == Keyboard.CODE_SPACE) {
13219a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                    mJustAddedAutoSpace = true;
13229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                }
1323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1327571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (mJustAddedAutoSpace && primaryCode == Keyboard.CODE_ENTER) {
13289a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            removeTrailingSpace();
13299a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = false;
13309a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        sendKeyChar((char)primaryCode);
13324ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
13334ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // Handle the case of ". ." -> " .." with auto-space if necessary
13344ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        // before changing the TextEntryState.
1335979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1336571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode == Keyboard.CODE_PERIOD) {
13374ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa            reswapPeriodAndSpace();
13384ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
13394ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.typedCharacter((char) primaryCode, true);
1341979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
1342571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && primaryCode != Keyboard.CODE_ENTER) {
1343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            swapPunctuationAndSpace();
13449fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            doubleSpace();
1346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1347979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
134855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            CharSequence typedWord = mWord.getTypedWord();
134955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
135055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
13514ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                if (ic != null) {
13524ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    CorrectionInfo correctionInfo = new CorrectionInfo(
13534ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                            mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
13544ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                    ic.commitCorrection(correctionInfo);
13554ca16dbd65150359c3884da7cb59a30f19abd4b7Tadashi G. Takaoka                }
135655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
135755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
135855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
135955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1361b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1363923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1364923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1366466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1369409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.handleClose();
1370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
13711679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
13721679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
13731679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.endSession();
1375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1377979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void saveWordInHistory(CharSequence result) {
1378979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mWord.size() <= 1) {
1379979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mWord.reset();
1380979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1382979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Skip if result is null. It happens in some edge case.
1383979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (TextUtils.isEmpty(result)) {
1384979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1386979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1387979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
1388979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final String resultCopy = result.toString();
1389979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        TypedWordAlternatives entry = new TypedWordAlternatives(resultCopy,
1390979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                new WordComposer(mWord));
1391979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mWordHistory.add(entry);
1392923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
13949fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isSuggestionsRequested() {
1395c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1396c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1398a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
13997599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private boolean isShowingPunctuationList() {
14007e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        return mSuggestPuncList == mCandidateView.getSuggestions();
14017599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14027599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private boolean isShowingSuggestionsStrip() {
14047599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
14057599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
14067599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
14077599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
14087599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCandidateStripVisible() {
14109fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isCorrecting())
14119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14129fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
14139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
14149fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
14159fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
14169fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1419409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
14205a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        mHandler.post(new Runnable() {
14215a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
14225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            public void run() {
14235a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                if (DEBUG) {
14245a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    Log.d(TAG, "Switch to keyboard view.");
14255a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                }
14265a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                View v = mKeyboardSwitcher.getInputView();
14275a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                if (v != null) {
14285a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    // Confirms that the keyboard view doesn't have parent view.
14295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    ViewParent p = v.getParent();
14305a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    if (p != null && p instanceof ViewGroup) {
14315a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                        ((ViewGroup) p).removeView(v);
14325a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    }
14335a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                    setInputView(v);
14345a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                }
14355a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                setCandidatesViewShown(isCandidateStripVisible());
14365a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                updateInputViewShown();
14375a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
14385a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
14395a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka        });
1440466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1441466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1442409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
14437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1444466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1445466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14467e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1447409220583333bdf06290dd9fd42f91b5c0d1b11asatok        if (mVoiceConnector.getAndResetIsShowingHint()) {
1448466741d8a78965b8509bf527344f289e50873092Mike LeBeau             setCandidatesView(mCandidateViewContainer);
1449466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1450466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1451466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
14527e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
14539ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (mCandidateView.isConfigCandidateHighlightFontColorEnabled()) {
14549ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.onAutoCorrectionStateChanged(
14559ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                        words.hasWordAboveAutoCorrectionScoreThreshold());
14569ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            }
1457466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1458466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1459466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1460409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
14611679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(null);
14621b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
14649fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1465409220583333bdf06290dd9fd42f91b5c0d1b11asatok                && !mVoiceConnector.isVoiceInputHighlighted()) {
1466923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1468466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14699fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1470ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1471923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1472923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1473979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        showSuggestions(mWord);
1474979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1475979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
14767e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords.Builder getTypedSuggestions(WordComposer word) {
14779ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka        return mSuggest.getSuggestedWordBuilder(mKeyboardSwitcher.getInputView(), word, null);
1478979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1479979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1480979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showCorrections(WordAlternatives alternatives) {
14811679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(null);
14827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = alternatives.getAlternatives();
14837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
14847e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), alternatives.getOriginalWord());
1485979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1486979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1487979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void showSuggestions(WordComposer word) {
1488979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // TODO Maybe need better way of retrieving previous word
1489e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1490979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mWordSeparators);
14917e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
14929ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mKeyboardSwitcher.getInputView(), word, prevWord);
1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14941b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani        int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
14951679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
14961b62ff1a3d61cd44ab88acdfcbdf0fc70a7e1b10Amith Yamasani
1497378a1b516d867671d292900c5d42aef3a0dc1556Ken Wakasa        boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
1498378a1b516d867671d292900c5d42aef3a0dc1556Ken Wakasa                && mSuggest.hasMinimalCorrection();
1499a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final CharSequence typedWord = word.getTypedWord();
1500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If we're in basic correct
1501a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
1502979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                (preferCapitalization()
1503979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                        && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
1504979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1505979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
1506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            correctionAvailable |= typedWordValid;
1507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15084a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
1509979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !word.isMostlyCaps();
1510979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        correctionAvailable &= !TextEntryState.isCorrecting();
1511979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1512a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1513a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1514a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // is 1, regardless of suggestion count.  Actually, in most cases, suggestion count is 1
1515a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // when typed word's length is 1, but we do always need to clear the previous state when
1516a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // the user starts typing a word (i.e. typed word's length == 1).
1517a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        if (typedWord.length() == 1 || builder.size() > 1
1518a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa                || mCandidateView.isShowingAddToDictionaryHint()) {
15199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(correctionAvailable);
15209fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        } else {
15219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
15229fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            if (previousSuggestions == mSuggestPuncList)
15239fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka                return;
15249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
15259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
15267e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1527979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
15284a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
15297e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
15307e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
15317e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
15329ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka            if (suggestedWords.hasAutoCorrectionWord()) {
15337e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1535923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1536923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1537923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1540ca26f20fa4903de46e374babbfba8c8a1a5cac93satok        setCandidatesViewShown(isCandidateStripVisible());
1541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1542923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1543979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean pickDefaultSuggestion() {
1544923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1545d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1546d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1547923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15496780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
1550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
1551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mJustAccepted = true;
155255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            pickSuggestion(mBestWord);
15539468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani            // Add the word to the auto dictionary if it's not a known word
1554979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
1555979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1556979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1557923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1558979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
15627e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
1563409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
15644f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1565979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        final boolean correcting = TextEntryState.isCorrecting();
15669a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        InputConnection ic = getCurrentInputConnection();
15679a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
15689a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
15699a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
15701b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
15711b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
15721b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            CompletionInfo ci = mApplicationSpecifiedCompletions[index];
1573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
1574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.commitCompletion(ci);
1575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1576923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1577923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1579923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1580b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
15819a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15829a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
15839a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15866a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
15876a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
1588979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion.length() == 1 && (isWordSeparator(suggestion.charAt(0))
1589979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || isSuggestedPunctuation(suggestion.charAt(0)))) {
1590979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1591979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1592979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
15937e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
159455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa            final char primaryCode = suggestion.charAt(0);
1595a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1596a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1597a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
15989a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
15999a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
16009a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
16016a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
16026a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
16039a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        mJustAccepted = true;
160455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        pickSuggestion(suggestion);
16059468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
16060c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1607979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
1608979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1609979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            addToBigramDictionary(suggestion, 1);
16100c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
1611979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
16127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                index, suggestions.mWords);
1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
1614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1615979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mAutoSpace && !correcting) {
1616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendSpace();
16179a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            mJustAddedAutoSpace = true;
1618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1619979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1620b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        final boolean showingAddToDictionaryHint = index == 0 && mCorrectionMode > 0
1621b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion)
1622b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                && !mSuggest.isValidWord(suggestion.toString().toLowerCase());
1623b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1624979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!correcting) {
1625b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1626b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1627b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1628571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true);
1629ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1630b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        } else if (!showingAddToDictionaryHint) {
1631364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1632979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
1633b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            clearSuggestions();
1634d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateOldSuggestions();
1635979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1636b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
163766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani            mCandidateView.showAddToDictionaryHint(suggestion);
163866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
16399a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
16409a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
16419a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1642923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1643a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1644979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1645979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Commits the chosen word to the text field and saves it for later
1646979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * retrieval.
1647979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param suggestion the suggestion picked by the user to be committed to
1648979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     *            the text field
1649979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
165055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private void pickSuggestion(CharSequence suggestion) {
1651b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1652b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
16531679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
1654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1656409220583333bdf06290dd9fd42f91b5c0d1b11asatok            mVoiceConnector.rememberReplacedWord(suggestion, mWordSeparators);
1657979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.commitText(suggestion, 1);
1658923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1659979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        saveWordInHistory(suggestion);
16609fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mHasValidSuggestions = false;
1661923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCommittedLength = suggestion.length();
1662b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.setPreferredLetters(null);
1663923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1664923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1665b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    /**
1666b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * Tries to apply any typed alternatives for the word if we have any cached alternatives,
1667b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * otherwise tries to find new corrections and completions for the word.
1668b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @param touching The word that the cursor is touching, with position information
1669b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     * @return true if an alternative was found, false otherwise.
1670b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani     */
1671e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    private boolean applyTypedAlternatives(EditingUtils.SelectedWord touching) {
1672b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // If we didn't find a match, search for result in typed word history
1673b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordComposer foundWord = null;
1674b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        WordAlternatives alternatives = null;
1675b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        for (WordAlternatives entry : mWordHistory) {
1676e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
1677b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                if (entry instanceof TypedWordAlternatives) {
1678b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    foundWord = ((TypedWordAlternatives) entry).word;
1679b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                }
1680b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                alternatives = entry;
1681b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                break;
1682b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1683b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
16841b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // If we didn't find a match, at least suggest corrections.
1685b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord == null
1686e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                && (mSuggest.isValidWord(touching.mWord)
1687e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        || mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
1688b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            foundWord = new WordComposer();
1689e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            for (int i = 0; i < touching.mWord.length(); i++) {
1690e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                foundWord.add(touching.mWord.charAt(i), new int[] {
1691e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    touching.mWord.charAt(i)
1692b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                });
1693b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1694e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            foundWord.setFirstCharCapitalized(Character.isUpperCase(touching.mWord.charAt(0)));
1695b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1696b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        // Found a match, show suggestions
1697b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (foundWord != null || alternatives != null) {
1698b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (alternatives == null) {
1699e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                alternatives = new TypedWordAlternatives(touching.mWord, foundWord);
1700b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1701b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            showCorrections(alternatives);
1702b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            if (foundWord != null) {
1703b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord = new WordComposer(foundWord);
1704b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            } else {
1705b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                mWord.reset();
1706b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            }
1707b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return true;
1708b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1709b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return false;
1710b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
1711b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1712979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void setOldSuggestions() {
1713409220583333bdf06290dd9fd42f91b5c0d1b11asatok        mVoiceConnector.setShowingVoiceSuggestions(false);
1714b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
1715b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            return;
1716b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
1717979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        InputConnection ic = getCurrentInputConnection();
1718979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (ic == null) return;
17199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions) {
1720b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Extract the selected or touching text
1721e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
1722b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    mLastSelectionStart, mLastSelectionEnd, mWordSeparators);
1723979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1724e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (touching != null && touching.mWord.length() > 1) {
1725b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.beginBatchEdit();
1726979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1727409220583333bdf06290dd9fd42f91b5c0d1b11asatok                if (!mVoiceConnector.applyVoiceAlternatives(touching)
1728409220583333bdf06290dd9fd42f91b5c0d1b11asatok                        && !applyTypedAlternatives(touching)) {
1729b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                    abortCorrection(true);
1730b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                } else {
1731979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    TextEntryState.selectedForCorrection();
1732e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    EditingUtils.underlineWord(ic, touching);
1733979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
1734b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1735b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                ic.endBatchEdit();
1736979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } else {
1737979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                abortCorrection(true);
1738ca26f20fa4903de46e374babbfba8c8a1a5cac93satok                setPunctuationSuggestions();  // Show the punctuation suggestions list
1739979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1740979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1741979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            abortCorrection(true);
1742979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1743979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1744979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1745ca26f20fa4903de46e374babbfba8c8a1a5cac93satok    private void setPunctuationSuggestions() {
17467e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(mSuggestPuncList);
17479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        setCandidatesViewShown(isCandidateStripVisible());
17486a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
17496a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1750979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToDictionaries(CharSequence suggestion, int frequencyDelta) {
1751979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1752979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1753979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1754979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1755979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1756979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1757979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1758979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1759979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * Adds to the UserBigramDictionary and/or AutoDictionary
1760979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     * @param addToBigramDictionary true if it should be added to bigram dictionary if possible
1761979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1762979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1763979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            boolean addToBigramDictionary) {
1764979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
17650c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
17660c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
17670c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1768979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1769979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1770979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1771979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1772e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
1773e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                || (!mSuggest.isValidWord(suggestion.toString())
1774e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        && !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
1775e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
1776e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1777979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1778e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1779e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            CharSequence prevWord = EditingUtils.getPreviousWord(getCurrentInputConnection(),
1780e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    mSentenceSeparators);
1781e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (!TextUtils.isEmpty(prevWord)) {
1782e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
1783979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
178432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
178532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
178632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
1787923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isCursorTouchingWord() {
1788923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        InputConnection ic = getCurrentInputConnection();
1789923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1790923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1791923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1792923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
179355b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toLeft.charAt(0))
179455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toLeft.charAt(0))) {
1795923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1796923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1797a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
179855b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isWordSeparator(toRight.charAt(0))
179955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                && !isSuggestedPunctuation(toRight.charAt(0))) {
1800923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1802923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1803923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1804a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1805dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) {
1806dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1807dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1808dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1809dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
1810923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void revertLastWord(boolean deleteChar) {
1811923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int length = mComposing.length();
18129fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!mHasValidSuggestions && length > 0) {
1813923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final InputConnection ic = getCurrentInputConnection();
1814c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = true;
1815504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence punctuation = ic.getTextBeforeCursor(1, 0);
1816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (deleteChar) ic.deleteSurroundingText(1, 0);
1817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int toDelete = mCommittedLength;
1818504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            final CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
1819504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            if (!TextUtils.isEmpty(toTheLeft) && isWordSeparator(toTheLeft.charAt(0))) {
1820923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                toDelete--;
1821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(toDelete, 0);
182330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // Re-insert punctuation only when the deleted character was word separator and the
182430be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            // composing text wasn't equal to the auto-corrected text.
182530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka            if (deleteChar
182630be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.isEmpty(punctuation) && isWordSeparator(punctuation.charAt(0))
182730be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                    && !TextUtils.equals(mComposing, toTheLeft)) {
1828504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.commitText(mComposing, 1);
1829504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.acceptedTyped(mComposing);
183030be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                ic.commitText(punctuation, 1);
183130be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                TextEntryState.typedCharacter(punctuation.charAt(0), true);
183230be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                // Clear composing text
183330be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mComposing.setLength(0);
1834504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            } else {
183530be3f9845c7b1d5ae14036f816e0f7c55939f37Tadashi G. Takaoka                mHasValidSuggestions = true;
1836504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                ic.setComposingText(mComposing, 1);
1837504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka                TextEntryState.backspace();
1838504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka            }
1839d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1841923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
1842c1e2e827b5d1bba59eb99d322dc101657ec28768Ken Wakasa            mJustReverted = false;
1843923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1846923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected String getWordSeparators() {
1847923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mWordSeparators;
1848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1849a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
1851923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        String separators = getWordSeparators();
1852923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return separators.contains(String.valueOf((char)code));
1853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1855979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSentenceSeparator(int code) {
1856923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mSentenceSeparators.contains(String.valueOf((char)code));
1857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1859923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void sendSpace() {
1860571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
1861b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1863923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
18650b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mWord.isFirstCharCapitalized();
1866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1868c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // Notify that language or mode have been changed and toggleLanguage will update KeyboaredID
1869c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
1870c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
18714ab730dbd34fad323063f2ffd31ce33de746668dsatok        toggleLanguage(true, true);
18724ab730dbd34fad323063f2ffd31ce33de746668dsatok    }
18734ab730dbd34fad323063f2ffd31ce33de746668dsatok
18744ab730dbd34fad323063f2ffd31ce33de746668dsatok    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
18753f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani    private void toggleLanguage(boolean reset, boolean next) {
1876de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        if (mSubtypeSwitcher.useSpacebarLanguageSwitcher()) {
18774ab730dbd34fad323063f2ffd31ce33de746668dsatok            mSubtypeSwitcher.toggleLanguage(reset, next);
18784ab730dbd34fad323063f2ffd31ce33de746668dsatok        }
18794ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
1880b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
18818b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final EditorInfo attribute = getCurrentInputEditorInfo();
1882c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int mode = initializeInputAttributesAndGetMode((attribute != null)
1883c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                ? attribute.inputType : 0);
1884d98c20b036ff02f99406dabb8cc4fdf4a51cd6c4Tadashi G. Takaoka        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
1885409220583333bdf06290dd9fd42f91b5c0d1b11asatok        switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
1886409220583333bdf06290dd9fd42f91b5c0d1b11asatok                mVoiceConnector.isVoiceButtonOnPrimary());
18870ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
1888b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
188936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
189036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
18915a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
189236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
189336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            String key) {
18940ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
18959502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        if (Settings.PREF_SELECTED_LANGUAGES.equals(key)) {
189636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mRefreshKeyboardRequired = true;
18979502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        } else if (Settings.PREF_RECORRECTION_ENABLED.equals(key)) {
18989502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            mReCorrectionEnabled = sharedPreferences.getBoolean(
18999502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                    Settings.PREF_RECORRECTION_ENABLED,
1900458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                    mResources.getBoolean(R.bool.default_recorrection_enabled));
190136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
190236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
190336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
19045a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
19058aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onSwipeDown() {
1906363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        if (mConfigSwipeDownDismissKeyboardEnabled)
1907363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka            handleClose();
1908923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1909923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19105a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1911923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onPress(int primaryCode) {
1912cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        if (mKeyboardSwitcher.isVibrateAndSoundFeedbackRequired()) {
1913cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
1914cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
1915cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
19161679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19171679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1918571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1919b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.onPressShift();
1920e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19216c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
192240a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
19236c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
1924681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
1925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1926923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19275a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1928923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onRelease(int primaryCode) {
19291679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
19303f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
19311679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        switcher.keyReleased();
19321679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1933571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
1934889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka            switcher.onReleaseShift();
1935e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
19366c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
193740a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
1938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1939a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1940a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // receive ringer mode changes to detect silent mode
1942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
1943923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1944923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1945923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateRingerMode();
1946923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1947923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
1950923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
1951923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1952923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager != null) {
1955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSilentMode = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
1956923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1957923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1958923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1959923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
1960923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
1961923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
1962923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
1963979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mKeyboardSwitcher.getInputView() != null) {
1964923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
1965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSoundOn && !mSilentMode) {
1968923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: Volume and enable should come from UI settings
1969923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // FIXME: These should be triggered after auto-repeat logic
1970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
1971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
1972571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
1973923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
1974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1975571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
1976923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
1977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1978571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
1979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
1980923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
1981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager.playSoundEffect(sound, FX_VOLUME);
1983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1985923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1986409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
1987923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!mVibrateOn) {
1988923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1989923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
19901679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
19911679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
19921679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
1993979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
199466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
1995923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1997923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
199871c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public void promoteToUserDictionary(String word, int frequency) {
199934386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        if (mUserDictionary.isValidWord(word)) return;
200034386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani        mUserDictionary.addWord(word, frequency);
200134386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani    }
200234386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
200371c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
20046516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        return mWord;
20056516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
20066516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
200771c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public boolean getPopupOn() {
2008979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mPopupOn;
2009979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2010979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2011e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
2012e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mHasDictionary = mSuggest != null ? mSuggest.hasMainDictionary() : false;
2013e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mAutoCorrectOn = (mAutoCorrectEnabled || mQuickFixes)
2014e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                && !mInputTypeNoAutoCorrect && mHasDictionary;
201532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        mCorrectionMode = (mAutoCorrectOn && mAutoCorrectEnabled)
2016e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
201732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani                : (mAutoCorrectOn ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
2018979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mCorrectionMode = (mBigramSuggestionEnabled && mAutoCorrectOn && mAutoCorrectEnabled)
2019979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2020e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2021e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2022e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2023e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2024e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
20250ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
202632e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
20270ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSuggest.setAutoTextEnabled(mQuickFixes
20284ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
202932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
203032e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
20317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private void updateSuggestionVisibility(SharedPreferences prefs) {
2032458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
20337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
20349502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2035458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
20367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2037458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
20387599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
20397599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
20407599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
20417599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
20427599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
20437599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2044466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
20459502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(Settings.class);
2046466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2047466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2048bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
20499502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        launchSettings(DebugSettings.class);
2050bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2051bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2052507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
2053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2054923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2055466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2057923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2058923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2060507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private void loadSettings(EditorInfo attribute) {
2061923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Get the settings preferences
206227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = mPrefs;
20634174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasa        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
20644174655e23734563775acb9e1e644b31b9e72fa5Ken Wakasa        mVibrateOn = vibrator != null && vibrator.hasVibrator()
20659502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                && prefs.getBoolean(Settings.PREF_VIBRATE_ON, false);
20669502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, false);
20679502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON,
20689b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                mResources.getBoolean(R.bool.config_default_popup_preview));
20699502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
20709502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        mQuickFixes = prefs.getBoolean(Settings.PREF_QUICK_FIXES, true);
2071a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
207227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
207327d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
20741b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        loadAndSetAutoCorrectionThreshold(prefs);
2075466741d8a78965b8509bf527344f289e50873092Mike LeBeau
207627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mVoiceConnector.loadSettings(attribute, prefs);
2077409220583333bdf06290dd9fd42f91b5c0d1b11asatok
2078e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
20790ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        updateAutoTextEnabled();
208027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        updateSuggestionVisibility(prefs);
208127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        SubtypeSwitcher.getInstance().loadSettings();
208236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
208336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2084b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    /**
20851b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka     *  Load Auto correction threshold from SharedPreferences, and modify mSuggest's threshold.
2086b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda     */
20871b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private void loadAndSetAutoCorrectionThreshold(SharedPreferences sp) {
2088b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // When mSuggest is not initialized, cannnot modify mSuggest's threshold.
2089b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (mSuggest == null) return;
20901b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When auto correction setting is turned off, the threshold is ignored.
2091b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        if (!isAutoCorrectEnabled(sp)) return;
2092b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
20931b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
20941b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
20959ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
20961b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String[] autoCorrectionThresholdValues = mResources.getStringArray(
20979ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.array.auto_correction_threshold_values);
20981b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        // When autoCrrectionThreshold is greater than 1.0, auto correction is virtually turned off.
20991b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        double autoCorrectionThreshold = Double.MAX_VALUE;
2100b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        try {
21011b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
21021b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
21031b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                autoCorrectionThreshold = Double.parseDouble(
21041b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                        autoCorrectionThresholdValues[arrayIndex]);
2105b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda            }
2106b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        } catch (NumberFormatException e) {
21071b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            // Whenever the threshold settings are correct, never come here.
21081b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            autoCorrectionThreshold = Double.MAX_VALUE;
21091b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            Log.w(TAG, "Cannot load auto correction threshold setting."
21101b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
21111b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + ", autoCorrectionThresholdValues: "
21121b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    + Arrays.toString(autoCorrectionThresholdValues));
2113b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        }
2114b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda        // TODO: This should be refactored :
21151b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        //           setAutoCorrectionThreshold should be called outside of this method.
21161b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mSuggest.setAutoCorrectionThreshold(autoCorrectionThreshold);
2117b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2118b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2119b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
21201b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String currentAutoCorrectionSetting = sp.getString(
21211b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                Settings.PREF_AUTO_CORRECTION_THRESHOLD,
21229ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                mResources.getString(R.string.auto_correction_threshold_mode_index_modest));
21231b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final String autoCorrectionOff = mResources.getString(
21249ecad8c2e8571ece6f3f7fbb19ceda5be7866cf0Tadashi G. Takaoka                R.string.auto_correction_threshold_mode_index_off);
21251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        return !currentAutoCorrectionSetting.equals(autoCorrectionOff);
2126b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2127b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
2128b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
2129b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda       // TODO: Define default value instead of 'true'.
21309502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka       return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTIONS, true);
2131b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda    }
2132b1abda8d62d654e876c4f781a07d724922c736e4Mitsuhiro Shimoda
21336a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private void initSuggestPuncList() {
21347e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (mSuggestPuncs != null || mSuggestPuncList != null)
21357e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            return;
21367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords.Builder builder = new SuggestedWords.Builder();
21377e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        String puncs = mResources.getString(R.string.suggested_punctuations);
21387e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (puncs != null) {
21397e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            for (int i = 0; i < puncs.length(); i++) {
21407e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                builder.addWord(puncs.subSequence(i, i + 1));
21416a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            }
21426a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
21437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncList = builder.build();
21447e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        mSuggestPuncs = puncs;
21456a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
21466a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2147979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private boolean isSuggestedPunctuation(int code) {
2148979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestPuncs.contains(String.valueOf((char)code));
2149979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2150979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void showOptionsMenu() {
2152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        AlertDialog.Builder builder = new AlertDialog.Builder(this);
2153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setCancelable(true);
2154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setIcon(R.drawable.ic_dialog_keyboard);
2155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setNegativeButton(android.R.string.cancel, null);
2156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence itemSettings = getString(R.string.english_ime_settings);
21579a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        CharSequence itemInputMethod = getString(R.string.selectInputMethod);
2158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        builder.setItems(new CharSequence[] {
2159c1ff28462eee5880267fd2eae4da389b25f6f3daKen Wakasa                itemInputMethod, itemSettings},
2160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                new DialogInterface.OnClickListener() {
2161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21625a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
2166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    case POS_SETTINGS:
2167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        launchSettings();
2168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        break;
2169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    case POS_METHOD:
217079efbed76f638be298493107fa2d0cd1b5eb529esatok                        mImm.showInputMethodPicker();
2171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        break;
2172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        });
2175c1ff28462eee5880267fd2eae4da389b25f6f3daKen Wakasa        builder.setTitle(mResources.getString(R.string.english_ime_input_options));
2176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog = builder.create();
2177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Window window = mOptionsDialog.getWindow();
2178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        WindowManager.LayoutParams lp = window.getAttributes();
2179979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
2180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
2181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.setAttributes(lp);
2182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
2183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mOptionsDialog.show();
2184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21867e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
21877e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2189a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2191923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
2193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mComposing=" + mComposing.toString());
21949fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
21969fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mHasValidSuggestions=" + mHasValidSuggestions);
2197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoCorrectOn=" + mAutoCorrectOn);
2198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mAutoSpace=" + mAutoSpace);
21991b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
2201923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mSoundOn=" + mSoundOn);
2202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mVibrateOn=" + mVibrateOn);
2203979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        p.println("  mPopupOn=" + mPopupOn);
2204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
22056e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2207a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2212a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
222334386e698876c0f29b2d5b54b44db1e32b562c47Amith Yamasani
22240ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    @Override
22250ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
22264ab730dbd34fad323063f2ffd31ce33de746668dsatok        SubtypeSwitcher.getInstance().updateSubtype(subtype);
22270ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
2228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2229