LatinIME.java revision bf7dd47329c23c846912b268d15e8083ffdaabde
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
20923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.SharedPreferences;
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
2736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
30123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaokaimport android.net.ConnectivityManager;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.SystemClock;
34bf96661d33d0126adb60a48880ceba1ff055d4a4satokimport android.preference.PreferenceActivity;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.preference.PreferenceManager;
36e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.text.TextUtils;
38979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.DisplayMetrics;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
4266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
458e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
468e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
49466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
51c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka
525ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils;
53c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils;
54c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.EditorInfoCompatUtils;
55c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputConnectionCompatUtils;
56c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
57c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
58c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputTypeCompatUtils;
591fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils;
60c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.LanguageSwitcherProxy;
61c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.VoiceProxy;
62c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.recorrection.Recorrection;
6383ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasaimport com.android.inputmethod.keyboard.Key;
64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
65c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
66c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
67055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher.KeyboardLayoutState;
68f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
69c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
70c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
71923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
72466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
73466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
74466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
75466741d8a78965b8509bf527344f289e50873092Mike LeBeau
76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
79c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaokapublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener,
80c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        CandidateView.Listener {
818efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    private static final String TAG = LatinIME.class.getSimpleName();
82979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
83409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
849e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka    private static boolean DEBUG;
85a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
868efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
878efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
888efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     *
918efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
9310dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok    @SuppressWarnings("dep-ann")
948efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
998efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
1008efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
1014199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1024199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1034199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1074199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1088efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
1099e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
110fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
114d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
115a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
116055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    private static final int SCREEN_ORIENTATION_CHANGE_DETECTION_DELAY = 2;
117055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    private static final int ACCUMULATE_START_INPUT_VIEW_DELAY = 20;
118de30f9f2d61c8dd06a150dbd7c71b560e8589a04Ken Wakasa    private static final int RESTORE_KEYBOARD_STATE_DELAY = 500;
119055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
120cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
121cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
122cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
123cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
124cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
125cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1267599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1277599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1287599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1297599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1307599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1317599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1327599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1337599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1347599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1357599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1367599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1377599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1387599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1397599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
14017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private Settings.Values mSettingsValues;
14117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
142e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private View mCandidateViewContainer;
1437a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka    private int mCandidateStripHeight;
144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CandidateView mCandidateView;
145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1461b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
147a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
148610f1dc8553cf2ed97e763a06a19380c4a6cd636satok    private InputMethodManagerCompatWrapper mImm;
1492fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1502fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1512fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
15271c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1530ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
154b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    private VoiceProxy mVoiceProxy;
1557a8dac55278cedd838be325f56b4c52d973c61f5satok    private Recorrection mRecorrection;
156a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
158979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
159f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard    private UserUnigramDictionary mUserUnigramDictionary;
160ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka    private boolean mIsUserDictionaryAvaliable;
16136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1620730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // TODO: Create an inner class to group options and pseudo-options to improve readability.
163c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
1640730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mShouldInsertMagicSpace;
165c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
166c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
167c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
168c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
1699318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa    private final StringBuilder mComposingStringBuilder = new StringBuilder();
1709318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa    private WordComposer mWordComposer = new WordComposer();
171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
172f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard    private boolean mHasUncommittedTypedChars;
1730730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // Magic space: a space that should disappear on space/apostrophe insertion, move after the
1740730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // punctuation on punctuation insertion, and become a real space on alpha char insertion.
1750730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private boolean mJustAddedMagicSpace; // This indicates whether the last char is a magic space.
1764733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // This indicates whether the last keypress resulted in processing of double space replacement
1774733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // with period-space.
1784733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private boolean mJustReplacedDoubleSpace;
179409220583333bdf06290dd9fd42f91b5c0d1b11asatok
18079efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
18179efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
182979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
18379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
18479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
185979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1864733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't
1874733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // "expect" it, it means the user actually moved the cursor.
1884733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private boolean mExpectingUpdateSelection;
189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
191a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
193bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa    private static float mFxVolume = -1.0f; // just a default value to be updated runtime
19417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private boolean mSilentModeOn; // System-wide current configuration
195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
196b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    // TODO: Move this flag to VoiceProxy
19781c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
198466741d8a78965b8509bf527344f289e50873092Mike LeBeau
19938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    // Member variables for remembering the current device orientation.
20038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    private int mDisplayOrientation;
20138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    private int mDisplayWidth;
20238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    private int mDisplayHeight;
20338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
204cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
205cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private BroadcastReceiver mDictionaryPackInstallReceiver =
206cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard            new DictionaryPackInstallBroadcastReceiver(this);
207cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
208dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
209dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
210dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
2114f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public final UIHandler mHandler = new UIHandler(this);
212d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
2134f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
214d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
215d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
216d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 2;
217d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_VOICE_RESULTS = 3;
218de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
219de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
220fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        private static final int MSG_SPACE_TYPED = 6;
221cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
22238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        private static final int MSG_CONFIRM_ORIENTATION_CHANGE = 8;
22338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        private static final int MSG_START_INPUT_VIEW = 9;
224055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        private static final int MSG_RESTORE_KEYBOARD_LAYOUT = 10;
22538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
22638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        private static class OrientationChangeArgs {
22738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            public final int mOldWidth;
22838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            public final int mOldHeight;
22938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            private int mRetryCount;
23038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
23138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            public OrientationChangeArgs(int oldw, int oldh) {
23238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                mOldWidth = oldw;
23338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                mOldHeight = oldh;
23438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                mRetryCount = 0;
23538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
23638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
23738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            public boolean hasTimedOut() {
23838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                mRetryCount++;
23938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                return mRetryCount >= 10;
24038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
24138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
24238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            public boolean hasOrientationChangeFinished(DisplayMetrics dm) {
24338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                return dm.widthPixels != mOldWidth && dm.heightPixels != mOldHeight;
24438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
24538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
2474f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UIHandler(LatinIME outerInstance) {
2484f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
2494f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
2504f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
2534f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinIME latinIme = getOuterInstance();
2544f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
255c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getKeyboardView();
256923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
257d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
2584f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.updateSuggestions();
259d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
260d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_OLD_SUGGESTIONS:
2614f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.mRecorrection.fetchAndDisplayRecorrectionSuggestions(
2624f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mVoiceProxy, latinIme.mCandidateView,
2639318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                        latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWordComposer,
2644f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mHasUncommittedTypedChars, latinIme.mLastSelectionStart,
2654f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mLastSelectionEnd, latinIme.mSettingsValues.mWordSeparators);
266d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
267d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
268de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
269d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
270cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            case MSG_SET_BIGRAM_PREDICTIONS:
2714f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.updateBigramPredictions();
27289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                break;
273d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
2744f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization()
275de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
276de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
277de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
27817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
27966432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
2804f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            (1.0f + latinIme.mSettingsValues.
2814f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                                    mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
28266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
28317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
284de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
2854f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mSettingsValues.mDurationOfFadeoutLanguageOnSpacebar);
286de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
287de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
28817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
28966432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
2904f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
29117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            (LatinKeyboard)msg.obj);
29217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
293d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
29438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            case MSG_CONFIRM_ORIENTATION_CHANGE: {
29538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                final OrientationChangeArgs args = (OrientationChangeArgs)msg.obj;
29638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                final Resources res = latinIme.mResources;
29738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                final DisplayMetrics dm = res.getDisplayMetrics();
29838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                if (args.hasTimedOut() || args.hasOrientationChangeFinished(dm)) {
29938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                    latinIme.setDisplayGeometry(res.getConfiguration(), dm);
30038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                } else {
30138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                    // It seems orientation changing is on going.
30238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                    postConfirmOrientationChange(args);
30338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                }
30438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                break;
30538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
30638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            case MSG_START_INPUT_VIEW:
30738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                latinIme.onStartInputView((EditorInfo)msg.obj, false);
30838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                break;
309055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            case MSG_RESTORE_KEYBOARD_LAYOUT:
310055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                removeMessages(MSG_UPDATE_SHIFT_STATE);
311055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                ((KeyboardLayoutState)msg.obj).restore();
312055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                break;
313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
316d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
317d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
3189b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS),
3194f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
320d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
321d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
322d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
323d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
324d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
325d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
326d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
327d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
328d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
329d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
330d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateOldSuggestions() {
331d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
332d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
3334f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateOldSuggestions);
334d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
335d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
336d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateOldSuggestions() {
337d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
338d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
339d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
340d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
341d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
34217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
3434f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateShiftState);
344d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
345d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
346d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
347d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
348d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
349d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
350cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void postUpdateBigramPredictions() {
351cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
3529b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS),
3534f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
35489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
35589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
356cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void cancelUpdateBigramPredictions() {
357cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
35889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
35989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
360d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
361d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
362d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
363de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
364d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
3654f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinIME latinIme = getOuterInstance();
366de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
367de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
3684f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView();
369de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
3704f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard();
371c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The language is always displayed when the delay is negative.
372c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                final boolean needsToDisplayLanguage = localeChanged
3734f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        || latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar < 0;
374de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
3754f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                if (latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar != 0) {
376c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
3774f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            : latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
3784f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            keyboard);
37917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
380c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The fadeout animation will start when the delay is positive.
3814f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                if (localeChanged
3824f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        && latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar > 0) {
383de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
3844f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar);
385de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
386de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
387de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
388fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
389fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void startDoubleSpacesTimer() {
390fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
391fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
3924f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDoubleSpacesTurnIntoPeriodTimeout);
393fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
394fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
395fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void cancelDoubleSpacesTimer() {
396fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
397fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
398fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
399fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public boolean isAcceptingDoubleSpaces() {
400fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            return hasMessages(MSG_SPACE_TYPED);
401fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
40238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
403055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        public void postRestoreKeyboardLayout() {
404055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            final LatinIME latinIme = getOuterInstance();
405055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            final KeyboardLayoutState state = latinIme.mKeyboardSwitcher.getKeyboardState();
406055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            if (state.isValid()) {
407055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                removeMessages(MSG_RESTORE_KEYBOARD_LAYOUT);
408055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                sendMessageDelayed(
409055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                        obtainMessage(MSG_RESTORE_KEYBOARD_LAYOUT, state),
410055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                        RESTORE_KEYBOARD_STATE_DELAY);
411055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            }
412055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        }
413055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
41438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        private void postConfirmOrientationChange(OrientationChangeArgs args) {
41538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            removeMessages(MSG_CONFIRM_ORIENTATION_CHANGE);
416055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            // Will confirm whether orientation change has finished or not again.
417055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_CONFIRM_ORIENTATION_CHANGE, args),
418055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                    SCREEN_ORIENTATION_CHANGE_DETECTION_DELAY);
41938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
42038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
42138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        public void startOrientationChanging(int oldw, int oldh) {
42238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            postConfirmOrientationChange(new OrientationChangeArgs(oldw, oldh));
423055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            final LatinIME latinIme = getOuterInstance();
424055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            latinIme.mKeyboardSwitcher.getKeyboardState().save();
425055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            postRestoreKeyboardLayout();
42638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
42738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
42838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        public boolean postStartInputView(EditorInfo attribute) {
42938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            if (hasMessages(MSG_CONFIRM_ORIENTATION_CHANGE) || hasMessages(MSG_START_INPUT_VIEW)) {
43038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                removeMessages(MSG_START_INPUT_VIEW);
431cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa                // Postpone onStartInputView by ACCUMULATE_START_INPUT_VIEW_DELAY and see if
432cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa                // orientation change has finished.
433055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_START_INPUT_VIEW, attribute),
434055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                        ACCUMULATE_START_INPUT_VIEW_DELAY);
43538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                return true;
43638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
43738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            return false;
43838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
43938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    }
44038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
44138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    private void setDisplayGeometry(Configuration conf, DisplayMetrics metric) {
44238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        mDisplayOrientation = conf.orientation;
44338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        mDisplayWidth = metric.widthPixels;
44438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        mDisplayHeight = metric.heightPixels;
445d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka    }
446923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
4477e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
4487e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
44927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
45027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
45127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
4526d9021527a38ba1e94225020389621a0d7227aa1satok        LanguageSwitcherProxy.init(this, prefs);
453bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        InputMethodManagerCompatWrapper.init(this);
454ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka        SubtypeSwitcher.init(this);
45527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
4567a8dac55278cedd838be325f56b4c52d973c61f5satok        Recorrection.init(this, prefs);
4575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette        AccessibilityUtils.init(this, prefs);
458363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
460363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
461bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        mImm = InputMethodManagerCompatWrapper.getInstance();
4628efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
4630ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
4640ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
4657a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection = Recorrection.getInstance();
4669e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka        DEBUG = LatinImeLogger.sDBG;
467363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
46817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
46917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
470363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
471363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
472fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
4739502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
474979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
4759502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
476979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
4770ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
478979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
479979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
4809502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
481979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
482979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
483979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
48438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        setDisplayGeometry(res.getConfiguration(), res.getDisplayMetrics());
485b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
486cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Register to receive ringer mode change and network state change.
487cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Also receive installation and removal of a dictionary pack.
488123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
489123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
490123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
492b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
493cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
494cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final IntentFilter packageFilter = new IntentFilter();
495cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
496cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
497cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addDataScheme(SCHEME_PACKAGE);
498cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
499646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard
500646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        final IntentFilter newDictFilter = new IntentFilter();
501646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        newDictFilter.addAction(
502646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard                DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
503646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
50536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
50617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    // Has to be package-visible for unit tests
50717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    /* package */ void loadSettings() {
50817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
50917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
51017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
51114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
512bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        updateSoundEffectVolume();
51317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    }
51417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
5150ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
516cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
517eaa10f44a4a0108a90803b1b28238842d3fb5addsatok        final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr);
51836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
519309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Resources res = mResources;
520309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
52114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        final ContactsDictionary oldContactsDictionary;
52236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
52314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            oldContactsDictionary = mSuggest.getContactsDictionary();
52436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
52514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        } else {
52614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            oldContactsDictionary = null;
52736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
528979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5298efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
530cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
53117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCorrectEnabled) {
53217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
53317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        }
53427023341658b4cf5430d18ddb94fd9502ecfe3cbTadashi G. Takaoka        updateAutoTextEnabled();
535e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
536cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserDictionary = new UserDictionary(this, localeStr);
537923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
538ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka        mIsUserDictionaryAvaliable = mUserDictionary.isEnabled();
539e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
54014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        resetContactsDictionary(oldContactsDictionary);
541e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
542f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        mUserUnigramDictionary
543f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                = new UserUnigramDictionary(this, this, localeStr, Suggest.DIC_USER_UNIGRAM);
544f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        mSuggest.setUserUnigramDictionary(mUserUnigramDictionary);
545e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
546f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        mUserBigramDictionary
547f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER_BIGRAM);
548e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
549e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
550e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
55136fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
552309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        Utils.setSystemLocale(res, savedLocale);
553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
55436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
55514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard    /**
55614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * Resets the contacts dictionary in mSuggest according to the user settings.
55714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     *
55814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * This method takes an optional contacts dictionary to use. Since the contacts dictionary
55914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * does not depend on the locale, it can be reused across different instances of Suggest.
56014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * The dictionary will also be opened or closed as necessary depending on the settings.
56114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     *
56214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * @param oldContactsDictionary an optional dictionary to use, or null
56314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     */
56414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard    private void resetContactsDictionary(final ContactsDictionary oldContactsDictionary) {
56514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        final boolean shouldSetDictionary = (null != mSuggest && mSettingsValues.mUseContactsDict);
56614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard
56714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        final ContactsDictionary dictionaryToUse;
56814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        if (!shouldSetDictionary) {
56914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // Make sure the dictionary is closed. If it is already closed, this is a no-op,
57014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // so it's safe to call it anyways.
57114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            if (null != oldContactsDictionary) oldContactsDictionary.close();
57214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            dictionaryToUse = null;
57314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        } else if (null != oldContactsDictionary) {
57414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // Make sure the old contacts dictionary is opened. If it is already open, this is a
57514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // no-op, so it's safe to call it anyways.
57614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            oldContactsDictionary.reopen(this);
57714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            dictionaryToUse = oldContactsDictionary;
57814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        } else {
57914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
58014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        }
58114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard
58214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        if (null != mSuggest) {
58314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            mSuggest.setContactsDictionary(dictionaryToUse);
58414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        }
585699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard    }
586699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard
587cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /* package private */ void resetSuggestMainDict() {
588cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
589eaa10f44a4a0108a90803b1b28238842d3fb5addsatok        final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr);
590cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
591cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
592cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
593cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
594466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
595466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
596e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
597e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
598e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
599979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
600923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
601cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
602b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.destroy();
603979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
604979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
607923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
608923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
609923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
610dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
611b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
61238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        if (conf.orientation != mDisplayOrientation) {
61338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            mHandler.startOrientationChanging(mDisplayWidth, mDisplayHeight);
6149351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            final InputConnection ic = getCurrentInputConnection();
615466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
616466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
6172fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
6182fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
619b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
6208b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
62181c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
623b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.onConfigurationChanged(conf);
62481c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
62588fc9d44186120f9edc5cf7ec0e2af85260fed04satok
62688fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
62788fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.onConfigurationChanged(conf);
628923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
629b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
630923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
631923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
6326c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
6336c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    }
6346c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka
6356c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    @Override
6366c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    public void setInputView(View view) {
6376c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        super.setInputView(view);
6386c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        mCandidateViewContainer = view.findViewById(R.id.candidates_container);
6396c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        mCandidateView = (CandidateView) view.findViewById(R.id.candidates);
640281e180c33b1dd88e8eae48f279736c529f529d2Tadashi G. Takaoka        if (mCandidateView != null)
641281e180c33b1dd88e8eae48f279736c529f529d2Tadashi G. Takaoka            mCandidateView.setListener(this, view);
642c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height);
643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
644923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
646c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    public void setCandidatesView(View view) {
647c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        // To ensure that CandidatesView will never be set.
648c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return;
649923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
650923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
651a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
652923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
653055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        mHandler.postRestoreKeyboardLayout();
65438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        if (mHandler.postStartInputView(attribute)) {
65538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            return;
65638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
65738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
65845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
659c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        LatinKeyboardView inputView = switcher.getKeyboardView();
6608e09172df1bb176cc899940862c56bed9b9aec4esatok
66189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (DEBUG) {
662f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka            Log.d(TAG, "onStartInputView: attribute:" + ((attribute == null) ? "none"
663f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka                    : String.format("inputType=0x%08x imeOptions=0x%08x",
664f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka                            attribute.inputType, attribute.imeOptions)));
665910b73127fa207dd26ec8124000262523b0aac0csatok        }
666923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
667979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
668923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
669923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
670923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
6718d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
6724ab730dbd34fad323063f2ffd31ce33de746668dsatok
673662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        TextEntryState.reset();
6746c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
675055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
676055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
677055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        // want to enable the voice button.
678055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        final VoiceProxy voiceIme = mVoiceProxy;
6793be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka        final int inputType = (attribute != null) ? attribute.inputType : 0;
6803be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType)
6813be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka                || InputTypeCompatUtils.isVisiblePasswordInputType(inputType));
682c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
683cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
684c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
685c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
686c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
6879318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        mComposingStringBuilder.setLength(0);
688f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
689c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
6900730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
6914733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mJustReplacedDoubleSpace = false;
692c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
69317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
69417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateCorrectionMode();
69517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateAutoTextEnabled();
69617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateSuggestionVisibility(mPrefs, mResources);
69717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
69817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
69917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
70017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard         }
70117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.loadSettings(attribute, mPrefs);
70217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // This will work only when the subtype is not supported.
70317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        LanguageSwitcherProxy.loadSettings();
70417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
705c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
706255486a5d067469e074f3649b3d2747e7a08aaa2Tadashi G. Takaoka            switcher.loadKeyboard(attribute, mSettingsValues);
707c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
708c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
70988110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka        if (mCandidateView != null)
71088110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka            mCandidateView.clear();
711c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShownInternal(isCandidateStripVisible(), /* needsInputViewShown */ false);
712c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
713c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
714c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
715240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn,
716240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard                mSettingsValues.mKeyPreviewPopupDismissDelay);
717c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
718c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // If we just entered a text field, maybe it has some old text that requires correction
7197a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.checkRecorrectionOnStart();
720c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
721055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        voiceIme.onStartInputView(inputView.getWindowToken());
722c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
723c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
724c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
725c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
726cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
727cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
728cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
7294b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
730c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
7310730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mShouldInsertMagicSpace = false;
732e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
7339fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
7341b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
7351b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
736dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
737cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
738cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
739cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // Make sure that passwords are not displayed in candidate view
740e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isPasswordInputType(inputType)
741e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
742cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
743cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
744e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)
745cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
7460730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = false;
747cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
7480730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard                mShouldInsertMagicSpace = true;
749cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
750e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)) {
751cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
752cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
753cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
754cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
755cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
756cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
757cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
758cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
759cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
760e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
76136ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
762cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
763cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
764cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
765cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
766cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
767cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
768cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
769cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
770cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
771cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
772cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
773cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
774cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
775cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
776cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
777cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
778923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
780923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
781923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
782e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    public void onWindowHidden() {
783e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        super.onWindowHidden();
784f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
785e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        if (inputView != null) inputView.closing();
786e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    }
787e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
788e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    @Override
789923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onFinishInput() {
790923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
791a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
792979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
793979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
794b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
795409220583333bdf06290dd9fd42f91b5c0d1b11asatok
796f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
797d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
798f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        if (mUserUnigramDictionary != null) mUserUnigramDictionary.flushPendingWrites();
799979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
800466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
801466741d8a78965b8509bf527344f289e50873092Mike LeBeau
802466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
8036495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    public void onFinishInputView(boolean finishingInput) {
8046495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
805055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        mKeyboardSwitcher.onFinishInputView();
806f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
8075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        if (inputView != null) inputView.cancelAllMessages();
808d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
809d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
810d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateOldSuggestions();
8116495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
8126495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
8136495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
814466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
815466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
816b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.showPunctuationHintIfNecessary();
817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
819923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
820923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
823923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
824923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
825466741d8a78965b8509bf527344f289e50873092Mike LeBeau
826466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
827466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
828466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
829025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
830025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
831466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
832466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
833466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
834466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
835466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
836466741d8a78965b8509bf527344f289e50873092Mike LeBeau
837b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
8384f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
841025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
842025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
843025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
844f2f971531904026663a98629eec6eccf83e32fafJean Chalard        if (!mExpectingUpdateSelection
845f2f971531904026663a98629eec6eccf83e32fafJean Chalard                && ((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars)
846b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                || mVoiceProxy.isVoiceInputHighlighted())
847025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                && (selectionChanged || candidatesCleared)) {
848025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            if (candidatesCleared) {
849025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // If the composing span has been cleared, save the typed word in the history for
850025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // recorrection before we reset the candidate strip.  Then, we'll be able to show
851025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                // suggestions for recorrection right away.
8529318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mRecorrection.saveRecorrectionSuggestion(mWordComposer, mComposingStringBuilder);
853025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa            }
8549318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mComposingStringBuilder.setLength(0);
855f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            mHasUncommittedTypedChars = false;
85689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (isCursorTouchingWord()) {
857cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.cancelUpdateBigramPredictions();
85889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.postUpdateSuggestions();
85989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            } else {
86089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                setPunctuationSuggestions();
86189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
862923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            TextEntryState.reset();
8639351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            final InputConnection ic = getCurrentInputConnection();
864923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
865923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.finishComposingText();
866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
867b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok            mVoiceProxy.setVoiceInputHighlighted(false);
8688558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        } else if (!mHasUncommittedTypedChars && !mExpectingUpdateSelection
8698558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa                && TextEntryState.isAcceptedDefault()) {
8708558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.reset();
871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
8724733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (!mExpectingUpdateSelection) {
8739318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mJustAddedMagicSpace = false; // The user moved the cursor.
8749318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mJustReplacedDoubleSpace = false;
8754733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
8764733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mExpectingUpdateSelection = false;
877d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
878466741d8a78965b8509bf527344f289e50873092Mike LeBeau
879979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
880979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
881979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
882466741d8a78965b8509bf527344f289e50873092Mike LeBeau
8837a8dac55278cedd838be325f56b4c52d973c61f5satok        mRecorrection.updateRecorrectionSelection(mKeyboardSwitcher,
8847a8dac55278cedd838be325f56b4c52d973c61f5satok                mCandidateView, candidatesStart, candidatesEnd, newSelStart,
8857a8dac55278cedd838be325f56b4c52d973c61f5satok                newSelEnd, oldSelStart, mLastSelectionStart,
8867a8dac55278cedd838be325f56b4c52d973c61f5satok                mLastSelectionEnd, mHasUncommittedTypedChars);
8877a8dac55278cedd838be325f56b4c52d973c61f5satok    }
8887a8dac55278cedd838be325f56b4c52d973c61f5satok
8897a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setLastSelection(int start, int end) {
8907a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionStart = start;
8917a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionEnd = end;
892923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
893923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
894c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
895c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
896c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
897c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * the candidates view when this happens, but only if the extracted text
898c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
899c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
900c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
901c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
902c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
903c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
9047a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
905c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
906c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
907c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
908c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
909c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
910c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
911c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
912c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * implementation hides the candidates view when a vertical movement
913c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
914c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
915c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
916c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * cause the candidate strip to disappear and re-appear.
917c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
918c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
919c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
9207a8dac55278cedd838be325f56b4c52d973c61f5satok        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
921c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
922c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
923c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
924c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
925923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
926923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
927979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
928c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka        mKeyboardSwitcher.onHideWindow();
929979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
930923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
9316e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
9326e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
9336e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
9346e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
935b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
9369fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.clearWordsInHistory();
937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
9411b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
942979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
943a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
944bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
945bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
946bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
947bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
948923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
949923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
9501b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
9511b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
9521b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
953b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
954923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
956a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
9577e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
9581b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
9595238df54ad3f648d09d5288f00b0a9d3c0593832Tadashi G. Takaoka                    .setTypedWordValid(false)
9605238df54ad3f648d09d5288f00b0a9d3c0593832Tadashi G. Takaoka                    .setHasMinimalSuggestion(false);
961979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
9627e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
963923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
964c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            setSuggestionStripShown(true);
965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
966923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
967923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
968c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) {
9697a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka        // TODO: Modify this if we support candidates with hard keyboard
9707e9615f218630d14ae5666ede2efd5f12d0a23c3Tadashi G. Takaoka        if (onEvaluateInputViewShown() && mCandidateViewContainer != null) {
9717a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final boolean shouldShowCandidates = shown
9727a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
9734b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka            if (isFullscreenMode()) {
9747a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // No need to have extra space to show the key preview.
9757a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setMinimumHeight(0);
976c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
977c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.GONE);
9787a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            } else {
9797a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // We must control the visibility of the suggestion strip in order to avoid clipped
9807a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                // key previews, even when we don't show the suggestion strip.
9817a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                mCandidateViewContainer.setVisibility(
9827a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        shouldShowCandidates ? View.VISIBLE : View.INVISIBLE);
9837a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            }
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
985923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
986a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
987c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private void setSuggestionStripShown(boolean shown) {
988c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
989543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
990543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
991543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
994f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
9952951aa7e93c36fbbaff48139f3ff0ff6b67d05b7Tadashi G. Takaoka        if (inputView == null || mCandidateViewContainer == null)
99646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
99746ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        final int containerHeight = mCandidateViewContainer.getHeight();
99846ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        int touchY = containerHeight;
9999e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
100046ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (mKeyboardSwitcher.isInputViewShown()) {
10017a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            if (mCandidateViewContainer.getVisibility() == View.VISIBLE) {
10027a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                touchY -= mCandidateStripHeight;
10039e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
10047a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchWidth = inputView.getWidth();
10057a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchHeight = inputView.getHeight() + containerHeight
10067a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
10077a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
10089e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
10097a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
10107a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        + " height=" + touchHeight);
10119e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
10127a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
10139e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
101446ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.contentTopInsets = touchY;
101546ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.visibleTopInsets = touchY;
1016923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1017a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1018923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
1019979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
10202811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka        final EditorInfo ei = getCurrentInputEditorInfo();
10212811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka        if (ei != null) {
10222811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka            final int imeOptions = ei.imeOptions;
10232811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka            if (EditorInfoCompatUtils.hasFlagNoFullscreen(imeOptions))
10242811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka                return false;
10252811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka            if ((imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0)
10262811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka                return false;
10272811841ab49b5c380a2e5b7f3e3d009db67f8e0aTadashi G. Takaoka        }
1028458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        final Resources res = mResources;
1029458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        DisplayMetrics dm = res.getDisplayMetrics();
1030979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        float displayHeight = dm.heightPixels;
1031979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // If the display is more than X inches high, don't go to fullscreen mode
1032458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa        float dimen = res.getDimension(R.dimen.max_height_for_fullscreen);
1033979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (displayHeight > dimen) {
1034979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return false;
1035979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1036979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return super.onEvaluateFullscreenMode();
1037979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1038979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1039979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1040979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
1041923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
1042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
1043e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
1044c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getKeyboardView() != null) {
1045c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                if (mKeyboardSwitcher.getKeyboardView().handleBack()) {
10466e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
10476e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
1048e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
1049e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
1050923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1051923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
1052923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1053923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1054923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
1055923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
1056923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
1057e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
1058e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
1059e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
1060e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
1061e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
1062e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
1063e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
1064e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
1065e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
1066e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
1067e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
10689351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                final InputConnection ic = getCurrentInputConnection();
1069e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
1070e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
1071e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
1072e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
1073e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
1074923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1075923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
1076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1077923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
10789351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    public void commitTyped(final InputConnection ic) {
10798558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        if (!mHasUncommittedTypedChars) return;
10808558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        mHasUncommittedTypedChars = false;
10818558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        if (mComposingStringBuilder.length() > 0) {
10829351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            if (ic != null) {
10839351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                ic.commitText(mComposingStringBuilder, 1);
1084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
10858558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            mCommittedLength = mComposingStringBuilder.length();
10868558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.acceptedTyped(mComposingStringBuilder);
1087f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            addToUserUnigramAndBigramDictionaries(mComposingStringBuilder,
1088f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                    UserUnigramDictionary.FREQUENCY_FOR_TYPED);
1089923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
10908558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        updateSuggestions();
1091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1092923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1093b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
10949351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
10951c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
109617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCap && ic != null && ei != null
109717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && ei.inputType != InputType.TYPE_NULL) {
1098b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
10991c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
1100b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
11011c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
11021c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
1103863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void swapSwapperAndSpace() {
1104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
1107863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
1108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
1109863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                && lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
1110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
1113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1114b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
11154ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
11164ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
11174ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1118863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard    private void maybeDoubleSpace() {
1119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mCorrectionMode == Suggest.CORRECTION_NONE) return;
1120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final InputConnection ic = getCurrentInputConnection();
1121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
11222b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard        final CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
1123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
11249351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                && Utils.canBeFollowedByPeriod(lastThree.charAt(0))
1125571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1126fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE
1127fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && mHandler.isAcceptingDoubleSpaces()) {
1128fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.cancelDoubleSpacesTimer();
1129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1133b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
11344733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mJustReplacedDoubleSpace = true;
1135fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        } else {
1136fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.startDoubleSpacesTimer();
1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1139a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
11409351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    // "ic" must not null
11419351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) {
114241a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
114341a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
114441a519729505a877844f2c57a33509c302dddbceKen Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
11454ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1146571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1147571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
114841a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
114941a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
115041a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
115141a519729505a877844f2c57a33509c302dddbceKen Wakasa
11529a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    private void removeTrailingSpace() {
11539a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        final InputConnection ic = getCurrentInputConnection();
11549a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
11559a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
11569a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
11579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1158571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
11599a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
11609a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
11619a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
11629a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1163c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
1164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
11666558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
11676558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1168d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1170923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1171923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1174923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1179a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1180e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
1181cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        if (isShowingOptionDialog()) return;
1182d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
1183d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            showSubtypeSelectorAndSettings();
118411b7febc0bea46a6afb30d7fa040b841eadd7410Ken Wakasa        } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, false /* exclude aux subtypes */)) {
1185d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            showOptionsMenu();
1186d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        } else {
1187d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            launchSettings();
11889a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
11899a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
11909a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1191cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    // Virtual codes representing custom requests.  These are used in onCustomRequest() below.
1192cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1;
1193cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa
1194cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    @Override
1195cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    public boolean onCustomRequest(int requestCode) {
1196cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        if (isShowingOptionDialog()) return false;
1197cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        switch (requestCode) {
1198cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        case CODE_SHOW_INPUT_METHOD_PICKER:
119911b7febc0bea46a6afb30d7fa040b841eadd7410Ken Wakasa            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, true /* include aux subtypes */)) {
120079efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
1201cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa                return true;
12029a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
1203cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa            return false;
12049a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
1205cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        return false;
12069a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
12079a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
12089a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
12099a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
12109a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
12119a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
12125f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
12135a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
12148aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1216571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1220b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1221b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
12224733609947c0ec74e460bd714fffca0518ade93aJean Chalard        final boolean lastStateOfJustReplacedDoubleSpace = mJustReplacedDoubleSpace;
12234733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mJustReplacedDoubleSpace = false;
1224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1225571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
12264733609947c0ec74e460bd714fffca0518ade93aJean Chalard            handleBackspace(lastStateOfJustReplacedDoubleSpace);
12274189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
12284733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
12294189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
12304189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1231571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
12324189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1233101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1234b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
12354189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1236e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
12374189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1238101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1239b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
12404189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1241571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
12424189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
12434189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
12444189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
12454189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1246e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1247e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
12484189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1249571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1250b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
12514189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1252d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case Keyboard.CODE_SHORTCUT:
125320cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
12544189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1255571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
125645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
12574733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // There are two cases for tab. Either we send a "next" event, that may change the
12584733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // focus but will never move the cursor. Or, we send a real tab keycode, which some
12594733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // applications may accept or ignore, and we don't know whether this will move the
12604733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // cursor or not. So actually, we don't really know.
12614733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // So to go with the safer option, we'd rather behave as if the user moved the
12624733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // cursor when they didn't than the opposite. We also expect that most applications
12634733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // will actually use tab only for focus movement.
12644733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // To sum it up: do not update mExpectingUpdateSelection here.
12654189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
12664189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
126717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isWordSeparator(primaryCode)) {
1268b5d17e52fcda39d540822e615bfb7ed5074e0034satok                handleSeparator(primaryCode, x, y);
12694189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
12708fbd55229243cb66c03d5ea1f79dfb39f596590dsatok                handleCharacter(primaryCode, keyCodes, x, y);
12714189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
12724733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
12734733609947c0ec74e460bd714fffca0518ade93aJean Chalard            break;
1274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1275b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1276dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1277dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1279a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
12805a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
12818aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1282b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.commitVoiceInput();
12839351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
1284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
12859fbfd5877305ed19a20663630b498b6b3fdae942satok        mRecorrection.abortRecorrection(false);
1286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
128755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
12889351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        maybeRemovePreviousPeriod(ic, text);
1289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1290923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1291b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
12925f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
12930730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = false;
1294dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1295923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
12975a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
12988aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
129983e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
13005f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
130183e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
130283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
13034733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private void handleBackspace(boolean justReplacedDoubleSpace) {
1304b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.logAndRevertVoiceInput()) return;
13054f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1306504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1307504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1308979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1309979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1310b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleBackspace();
13114f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
13129ae24750f462cbd94b362fe54a952c86cfb05e5fKen Wakasa        final boolean deleteChar = !mHasUncommittedTypedChars;
1313f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
13149318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            final int length = mComposingStringBuilder.length();
1315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
13169318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mComposingStringBuilder.delete(length - 1, length);
13179318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mWordComposer.deleteLast();
13189318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                ic.setComposingText(mComposingStringBuilder, 1);
13199318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                if (mComposingStringBuilder.length() == 0) {
1320f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                    mHasUncommittedTypedChars = false;
1321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
132289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                if (1 == length) {
132389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // 1 == length means we are about to erase the last character of the word,
132489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // so we can show bigrams.
1325cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                    mHandler.postUpdateBigramPredictions();
132689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                } else {
132789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // length > 1, so we still have letters to deduce a suggestion from.
132889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    mHandler.postUpdateSuggestions();
132989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                }
1330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1334d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1335504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1337662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isUndoCommit()) {
13389351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            revertLastWord(ic);
1339979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1340923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1341504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
13424733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (justReplacedDoubleSpace) {
13439351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            if (revertDoubleSpace(ic)) {
13449351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                ic.endBatchEdit();
13459351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                return;
13464733609947c0ec74e460bd714fffca0518ade93aJean Chalard            }
13474733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
1348504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1349504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1350dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1351923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
13526558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
13536558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
135455b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
13556558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
13566558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
13576558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
13586558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
13596558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
13609351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                revertLastWord(ic);
13616558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
13636558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
13646558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
13656558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1368979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
137145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
137245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
1373b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
1374b2707856aba4fc9b063f26305f1fb603b19c1701satok                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
137545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
137645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
137745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
137845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
137945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
138045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
138145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
138245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
138345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
138445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
1385b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
138645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
1387b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionNext(ic);
1388b2707856aba4fc9b063f26305f1fb603b19c1701satok        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
138945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
1390b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionPrevious(ic);
139145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
139245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
139345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
13948fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    private void handleCharacter(int primaryCode, int[] keyCodes, int x, int y) {
1395b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleCharacter();
13964f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
139717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceStripper(primaryCode)) {
13980730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            removeTrailingSpace();
13990730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        }
14000730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard
1401863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mLastSelectionStart == mLastSelectionEnd) {
14029fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1403b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        }
14044f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1405e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
14063889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa        if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code))
14073889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa                && isSuggestionsRequested() && !isCursorTouchingWord()) {
1408f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            if (!mHasUncommittedTypedChars) {
1409f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
14109318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mComposingStringBuilder.setLength(0);
14119318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mRecorrection.saveRecorrectionSuggestion(mWordComposer, mBestWord);
14129318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mWordComposer.reset();
14137e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
141635f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
1417f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1418eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1419eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1420eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1421eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1422e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1423e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
142435f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                // In some locales, such as Turkish, Character.toUpperCase() may return a wrong
142535f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                // character because it doesn't take care of locale.
142635f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                final String upperCaseString = new String(new int[] {code}, 0, 1)
142735f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                        .toUpperCase(mSubtypeSwitcher.getInputLocale());
142835f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) {
142935f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                    code = upperCaseString.codePointAt(0);
143012a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
143112a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
143235f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                    onTextInput(upperCaseString);
143312a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
143412a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1435979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1436923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1437f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
14389318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            if (mComposingStringBuilder.length() == 0 && switcher.isAlphabetMode()
1439f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    && switcher.isShiftedOrShiftLocked()) {
14409318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mWordComposer.setFirstCharCapitalized(true);
1441923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
14429318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mComposingStringBuilder.append((char) code);
14439318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mWordComposer.add(code, keyCodes, x, y);
14449351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            final InputConnection ic = getCurrentInputConnection();
1445923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
14461c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
14479318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                if (mWordComposer.size() == 1) {
14489318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                    mWordComposer.setAutoCapitalized(getCurrentAutoCapsState());
14491c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
14509318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                ic.setComposingText(mComposingStringBuilder, 1);
1451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1452d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1453923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1454e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1455923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
145617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mJustAddedMagicSpace && mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1457863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            swapSwapperAndSpace();
1458863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        } else {
1459863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            mJustAddedMagicSpace = false;
1460863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1461863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1462b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1463979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
146417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y);
1465923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1466923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1467b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private void handleSeparator(int primaryCode, int x, int y) {
1468b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleSeparator();
14694f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
147055b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
14716558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
1472cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1473d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
14746558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
14756558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
14781b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1479923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1480923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
14819fbfd5877305ed19a20663630b498b6b3fdae942satok            mRecorrection.abortRecorrection(false);
1482923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1483f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1485a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1488f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard            final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
1489c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa                    && !mInputTypeNoAutoCorrect;
149017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
1491b5d17e52fcda39d540822e615bfb7ed5074e0034satok                pickedDefault = pickDefaultSuggestion(primaryCode);
1492923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1494923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
14964ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1497863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (mJustAddedMagicSpace) {
149817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1499863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1500863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                swapSwapperAndSpace();
1501863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            } else {
150217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (mSettingsValues.isMagicSpaceStripper(primaryCode)) removeTrailingSpace();
1503863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                sendKeyChar((char)primaryCode);
1504863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                mJustAddedMagicSpace = false;
1505863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            }
15060730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        } else {
15070730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendKeyChar((char)primaryCode);
15084ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
15094ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1510863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        if (isSuggestionsRequested() && primaryCode == Keyboard.CODE_SPACE) {
1511863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            maybeDoubleSpace();
1512863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1513863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1514b5d17e52fcda39d540822e615bfb7ed5074e0034satok        TextEntryState.typedCharacter((char) primaryCode, true, x, y);
151589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
1516979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (pickedDefault) {
15179318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            CharSequence typedWord = mWordComposer.getTypedWord();
151855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            TextEntryState.backToAcceptedDefault(typedWord);
151955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
1520b2707856aba4fc9b063f26305f1fb603b19c1701satok                InputConnectionCompatUtils.commitCorrection(
152189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                        ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
152255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                if (mCandidateView != null)
152355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    mCandidateView.onAutoCorrectionInverted(mBestWord);
152455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            }
152589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
152689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (Keyboard.CODE_SPACE == primaryCode) {
152789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isCursorTouchingWord()) {
152889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateSuggestions();
152989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateOldSuggestions();
1530cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.postUpdateBigramPredictions();
153189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
153289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
153389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Set punctuation right away. onUpdateSelection will fire but tests whether it is
153489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // already displayed or not, so it's okay.
153555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1536923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1537b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1538923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1540923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1542466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1544923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1545b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleClose();
1546923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
1547c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
15481679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
15491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
15527a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isSuggestionsRequested() {
1553c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1554c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1555923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1556a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
15577a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingPunctuationList() {
155817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSuggestPuncList == mCandidateView.getSuggestions();
15597599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
15607599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
15617a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingSuggestionsStrip() {
15627599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
15637599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
156438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                        && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT);
15657599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
15667599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
15679fbfd5877305ed19a20663630b498b6b3fdae942satok    public boolean isCandidateStripVisible() {
1568b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa        if (mCandidateView == null)
1569b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1570952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting())
15719fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
15729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
15739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
15749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
15759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
15769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1577923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1579409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1580060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1581060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1582060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1583c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        View v = mKeyboardSwitcher.getKeyboardView();
1584060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1585060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1586060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1587060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1588060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
15895a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1590060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1591060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1592c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShown(isCandidateStripVisible());
1593060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1594060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1595466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1596466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1597409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
15987e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1599466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1600466741d8a78965b8509bf527344f289e50873092Mike LeBeau
16017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1602466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (mCandidateView != null) {
16037e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            mCandidateView.setSuggestions(words);
16045e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka            mKeyboardSwitcher.onAutoCorrectionStateChanged(
16055e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka                    words.hasWordAboveAutoCorrectionScoreThreshold());
1606466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1607466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1608466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1609409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
16119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1612b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                && !mVoiceProxy.isVoiceInputHighlighted()) {
1613923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1615466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1616f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
1617ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1619923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1620979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
16219318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        final WordComposer wordComposer = mWordComposer;
16229f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: May need a better way of retrieving previous word
162340f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        final InputConnection ic = getCurrentInputConnection();
162440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        final CharSequence prevWord;
162540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        if (null == ic) {
162640f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            prevWord = null;
162740f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        } else {
162840f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
162940f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        }
163040f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        // getSuggestedWordBuilder handles gracefully a null value of prevWord
163140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
1632043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard                mKeyboardSwitcher.getKeyboardView(), wordComposer, prevWord,
1633043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard                mKeyboardSwitcher.getLatinKeyboard().getProximityInfo());
1634923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
16358558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
16369318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        final CharSequence typedWord = wordComposer.getTypedWord();
1637bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Here, we want to promote a whitelisted word if exists.
1638bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
1639bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
1640979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1641979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
16428558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            autoCorrectionAvailable |= typedWordValid;
1643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16444a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
16458558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        autoCorrectionAvailable &= !wordComposer.isMostlyCaps();
16468558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        autoCorrectionAvailable &= !TextEntryState.isRecorrecting();
1647979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1648a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1649a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1650f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1651f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1652f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1653f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1654fe1a6d961cf039357f061482461e4d2e951ad346satok        if (typedWord != null) {
1655fe1a6d961cf039357f061482461e4d2e951ad346satok            if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid
1656fe1a6d961cf039357f061482461e4d2e951ad346satok                    || mCandidateView.isShowingAddToDictionaryHint()) {
1657fe1a6d961cf039357f061482461e4d2e951ad346satok                builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion(
16588558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa                        autoCorrectionAvailable);
1659fe1a6d961cf039357f061482461e4d2e951ad346satok            } else {
1660fe1a6d961cf039357f061482461e4d2e951ad346satok                final SuggestedWords previousSuggestions = mCandidateView.getSuggestions();
1661fe1a6d961cf039357f061482461e4d2e951ad346satok                if (previousSuggestions == mSettingsValues.mSuggestPuncList)
1662fe1a6d961cf039357f061482461e4d2e951ad346satok                    return;
1663fe1a6d961cf039357f061482461e4d2e951ad346satok                builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
1664fe1a6d961cf039357f061482461e4d2e951ad346satok            }
16659fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
16667e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1667979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
16684a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
16699fbfd5877305ed19a20663630b498b6b3fdae942satok    public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
16707e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
16717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
167214e427d5bb13d59d23fb317ef90a6c44ae279425satok            if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) {
167382411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
167482411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
16757e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1676923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1680923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1681923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1682c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShown(isCandidateStripVisible());
1683923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1684923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1685b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private boolean pickDefaultSuggestion(int separatorCode) {
1686923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Complete any pending candidate query first
1687d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1688d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1689923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1690923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
16916780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
16929318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode);
16934733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
16941fef530ec7626fa16777f52b48191e61db8f46d4satok            commitBestWord(mBestWord);
1695f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            // Add the word to the user unigram dictionary if it's not a known word
1696f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            addToUserUnigramAndBigramDictionaries(mBestWord,
1697f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                    UserUnigramDictionary.FREQUENCY_FOR_TYPED);
1698979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1700979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1701923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1702923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1703c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
1704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
17057e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        SuggestedWords suggestions = mCandidateView.getSuggestions();
170617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
170717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
17084f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1709952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        final boolean recorrecting = TextEntryState.isRecorrecting();
17109351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
17119a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
17129a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
17139a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
17141b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
17151b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
1716923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
17179351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
17189351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                ic.commitCompletion(completionInfo);
1719923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1720923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1721923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mCandidateView != null) {
1722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mCandidateView.clear();
1723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1724b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
17259a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
17269a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
17279a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1728923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1729923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
17306a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
17316a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
173217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0))
173317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) {
1734979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1735979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1736979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
17377e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
1738863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // Find out whether the previous character is a space. If it is, as a special case
1739863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // for punctuation entered through the suggestion strip, it should be considered
1740863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a magic space even if it was a normal space. This is meant to help in case the user
1741863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // pressed space on purpose of displaying the suggestion strip punctuation.
174283ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa            final int rawPrimaryCode = suggestion.charAt(0);
174383ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa            // Maybe apply the "bidi mirrored" conversions for parentheses
174483ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa            final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
17458da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            final int primaryCode = keyboard.mIsRtlKeyboard
174683ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa                    ? Key.getRtlParenthesisCode(rawPrimaryCode) : rawPrimaryCode;
174783ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa
1748eaa10f44a4a0108a90803b1b28238842d3fb5addsatok            final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : "";
17491f050f634820a1d980e8a91f3a962bcd1fc242e3satok            final int toLeft = (ic == null || TextUtils.isEmpty(beforeText))
17501f050f634820a1d980e8a91f3a962bcd1fc242e3satok                    ? 0 : beforeText.charAt(0);
17514f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            final boolean oldMagicSpace = mJustAddedMagicSpace;
1752863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            if (Keyboard.CODE_SPACE == toLeft) mJustAddedMagicSpace = true;
1753a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka            onCodeInput(primaryCode, new int[] { primaryCode },
1754a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1755a96574fdd5e38a237a35b21a2b7c20a29138c648Tadashi G. Takaoka                    KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
17564f3b59711f6985d39e0cc908d2431ae6715d9b26Jean Chalard            mJustAddedMagicSpace = oldMagicSpace;
17579a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
17589a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
17599a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
17606a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
17616a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
1762f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
176389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // If we are not composing a word, then it was a suggestion inferred from
176489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // context - no user input. We should reset the word composer.
17659318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mWordComposer.reset();
176689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
17674733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mExpectingUpdateSelection = true;
17681fef530ec7626fa16777f52b48191e61db8f46d4satok        commitBestWord(suggestion);
17699468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
17700c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1771f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            addToUserUnigramAndBigramDictionaries(suggestion,
1772f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                    UserUnigramDictionary.FREQUENCY_FOR_PICKED);
1773979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1774bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToOnlyBigramDictionary(suggestion, 1);
17750c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
17769318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        LatinImeLogger.logOnManualSuggestion(mComposingStringBuilder.toString(),
17779318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                suggestion.toString(), index, suggestions.mWords);
17789318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion);
1779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
17800730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        if (mShouldInsertMagicSpace && !recorrecting) {
17810730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendMagicSpace();
1782923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1783979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1784c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa        // We should show the "Touch again to save" hint if the user pressed the first entry
1785c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa        // AND either:
17867f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
1787c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa        //   AND mSuggest.hasMainDictionary() is false)
17887f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
17897f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
17907f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
17917f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
17927f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
1793bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
1794bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                // If there is no dictionary the hint should be shown.
1795c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa                && (!mSuggest.hasMainDictionary()
1796bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        // If "suggestion" is not in the dictionary, the hint should be shown.
1797bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        || !AutoCorrection.isValidWord(
1798bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                                mSuggest.getUnigramDictionaries(), suggestion, true));
1799b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1800952cb7e973bbc4c09728cb5967505f84c80c8bd6Ken Wakasa        if (!recorrecting) {
1801b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1802b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // we just did a correction, in which case we need to stay in
1803b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani            // TextEntryState.State.PICKED_SUGGESTION state.
1804b5d17e52fcda39d540822e615bfb7ed5074e0034satok            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
1805b5d17e52fcda39d540822e615bfb7ed5074e0034satok                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1806777118a40a363ccab69a00016d3156066513cb78Jean Chalard        }
1807777118a40a363ccab69a00016d3156066513cb78Jean Chalard        if (!showingAddToDictionaryHint) {
1808364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1809979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
181041ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            updateBigramPredictions();
181141ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // Updating the predictions right away may be slow and feel unresponsive on slower
181241ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // terminals. On the other hand if we just postUpdateBigramPredictions() it will
181341ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // take a noticeable delay to update them which may feel uneasy.
1814979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1815b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
1816ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka            if (mIsUserDictionaryAvaliable) {
1817ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka                mCandidateView.showAddToDictionaryHint(suggestion);
1818ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka            } else {
1819ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
1820ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka            }
182166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
18229a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
18239a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
18249a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1826a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1827979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
18288558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa     * Commits the chosen word to the text field and saves it for later retrieval.
1829979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
18301fef530ec7626fa16777f52b48191e61db8f46d4satok    private void commitBestWord(CharSequence bestWord) {
18319351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final KeyboardSwitcher switcher = mKeyboardSwitcher;
1832b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
18331679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
18349351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
1835923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
18361fef530ec7626fa16777f52b48191e61db8f46d4satok            mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators);
18371fef530ec7626fa16777f52b48191e61db8f46d4satok            SuggestedWords suggestedWords = mCandidateView.getSuggestions();
18381fef530ec7626fa16777f52b48191e61db8f46d4satok            ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
18391fef530ec7626fa16777f52b48191e61db8f46d4satok                    this, bestWord, suggestedWords), 1);
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
18419318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        mRecorrection.saveRecorrectionSuggestion(mWordComposer, bestWord);
1842f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
18431fef530ec7626fa16777f52b48191e61db8f46d4satok        mCommittedLength = bestWord.length();
1844923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1845923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
184689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    private static final WordComposer sEmptyWordComposer = new WordComposer();
184741ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard    public void updateBigramPredictions() {
184889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (mSuggest == null || !isSuggestionsRequested())
184989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            return;
185089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
185117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mBigramPredictionEnabled) {
1852cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            setPunctuationSuggestions();
1853cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            return;
1854cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        }
1855cb3320179d39a7983874697a0aa428b127675c9dJean Chalard
185689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
185717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
185889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
1859043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard                mKeyboardSwitcher.getKeyboardView(), sEmptyWordComposer, prevWord,
1860043f7841985916717f4fa821fe3e423daf3ff2f5Jean Chalard                mKeyboardSwitcher.getLatinKeyboard().getProximityInfo());
186189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
186289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (builder.size() > 0) {
186389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Explicitly supply an empty typed word (the no-second-arg version of
186489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // showSuggestions will retrieve the word near the cursor, we don't want that here)
186589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            showSuggestions(builder.build(), "");
186689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
186789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isShowingPunctuationList()) setPunctuationSuggestions();
186889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
186989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    }
187089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
18717a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setPunctuationSuggestions() {
187217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        setSuggestions(mSettingsValues.mSuggestPuncList);
1873c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShown(isCandidateStripVisible());
18746a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
18756a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1876f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard    private void addToUserUnigramAndBigramDictionaries(CharSequence suggestion,
1877f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            int frequencyDelta) {
1878979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
1879979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1880979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1881bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
1882979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
1883979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1884979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1885979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
1886f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard     * Adds to the UserBigramDictionary and/or UserUnigramDictionary
1887bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
1888979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
1889979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
1890bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            boolean selectedANotTypedWord) {
1891979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
1892bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
18930c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
18940c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
18950c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
1896979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
1897979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
1898979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
1899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1900bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
1901f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        final boolean selectedATypedWordAndItsInUserUnigramDic =
1902f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                !selectedANotTypedWord && mUserUnigramDictionary.isValidWord(suggestion);
1903bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean isValidWord = AutoCorrection.isValidWord(
1904bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), suggestion, true);
1905f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        final boolean needsToAddToUserUnigramDictionary = selectedATypedWordAndItsInUserUnigramDic
1906bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                || !isValidWord;
1907f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        if (needsToAddToUserUnigramDictionary) {
1908f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            mUserUnigramDictionary.addWord(suggestion.toString(), frequencyDelta);
1909e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
1910979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1911e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
1912863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // We don't want to register as bigrams words separated by a separator.
1913863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // For example "I will, and you too" : we don't want the pair ("will" "and") to be
1914863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a bigram.
191540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            final InputConnection ic = getCurrentInputConnection();
191640f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            if (null != ic) {
191740f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                final CharSequence prevWord =
191840f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                        EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
191940f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                if (!TextUtils.isEmpty(prevWord)) {
192040f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                    mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
192140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                }
1922979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
192332e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
192432e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
192532e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
19267a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isCursorTouchingWord() {
19279351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
1928923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
1929923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
1930923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
1931923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
193217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toLeft.charAt(0))
193317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) {
1934923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1935923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1936a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
193717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toRight.charAt(0))
193817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) {
1939923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1940923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1941923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
1942923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1943a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
19449351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    // "ic" must not null
19459351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) {
1946dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
1947dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
1948dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
1949dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
19509351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    // "ic" must not null
19519351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private void revertLastWord(final InputConnection ic) {
19528558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) {
1953923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
19548558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            return;
19558558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        }
19568558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa
19579351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final CharSequence separator = ic.getTextBeforeCursor(1, 0);
195820c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa        ic.deleteSurroundingText(1, 0);
195920c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa        final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
196020c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa        ic.deleteSurroundingText(mCommittedLength, 0);
19619351550dc6af7859e5280e16144c9386a37b976dKen Wakasa
19629351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        // Re-insert "separator" only when the deleted character was word separator and the
19639351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        // composing text wasn't equal to the auto-corrected text which can be found before
19649351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        // the cursor.
19659351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        if (!TextUtils.isEmpty(separator)
19669351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                && mSettingsValues.isWordSeparator(separator.charAt(0))
196720c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa                && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) {
19688558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            ic.commitText(mComposingStringBuilder, 1);
19698558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.acceptedTyped(mComposingStringBuilder);
19709351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            ic.commitText(separator, 1);
19719351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            TextEntryState.typedCharacter(separator.charAt(0), true,
19728558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
19738558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            // Clear composing text
19748558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            mComposingStringBuilder.setLength(0);
19758558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        } else {
19768558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            mHasUncommittedTypedChars = true;
19778558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            ic.setComposingText(mComposingStringBuilder, 1);
19788558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.backspace();
1979923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
19808558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        mHandler.cancelUpdateBigramPredictions();
19818558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        mHandler.postUpdateSuggestions();
1982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19849351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    // "ic" must not null
19859351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private boolean revertDoubleSpace(final InputConnection ic) {
19864733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mHandler.cancelDoubleSpacesTimer();
19874733609947c0ec74e460bd714fffca0518ade93aJean Chalard        // Here we test whether we indeed have a period and a space before us. This should not
19884733609947c0ec74e460bd714fffca0518ade93aJean Chalard        // be needed, but it's there just in case something went wrong.
19894733609947c0ec74e460bd714fffca0518ade93aJean Chalard        final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
19904733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (!". ".equals(textBeforeCursor))
19914733609947c0ec74e460bd714fffca0518ade93aJean Chalard            return false;
19924733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.beginBatchEdit();
19934733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.deleteSurroundingText(2, 0);
19944733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.commitText("  ", 1);
19954733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.endBatchEdit();
19964733609947c0ec74e460bd714fffca0518ade93aJean Chalard        return true;
19974733609947c0ec74e460bd714fffca0518ade93aJean Chalard    }
19984733609947c0ec74e460bd714fffca0518ade93aJean Chalard
1999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
200017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.isWordSeparator(code);
2001923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2002923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20030730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private void sendMagicSpace() {
2004571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
20050730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        mJustAddedMagicSpace = true;
2006b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
2007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2008923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2009923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
20109318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        return mWordComposer.isFirstCharCapitalized();
2011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2012923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
201388fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
2014c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
2015c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
201655303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka        if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
201755303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka            // Before Honeycomb, Voice IME is in LatinIME and it changes the current input view,
201855303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka            // so that we need to re-create the keyboard input view here.
201955303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka            setInputView(mKeyboardSwitcher.onCreateInputView());
202055303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka        }
20214ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
2022255486a5d067469e074f3649b3d2747e7a08aaa2Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettingsValues);
20230ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
202417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
202536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
202636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
20275a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
2028e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPress(int primaryCode, boolean withSliding) {
2029055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
2030055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        switcher.registerWindowWidth();
2031055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        if (switcher.isVibrateAndSoundFeedbackRequired()) {
2032cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            vibrate();
2033cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka            playKeyClick(primaryCode);
2034cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
20351679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
2036571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
2037e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onPressShift(withSliding);
2038e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
20396c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
204040a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
20416c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
2042681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
2043923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2044923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
20455a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
2046e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onRelease(int primaryCode, boolean withSliding) {
20471679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
20483f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
20491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
2050571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
2051e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onReleaseShift(withSliding);
2052e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
20536c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
205440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
2055923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2056a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2057a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2058123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
2059923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
2060923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
2061923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2062123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
2063123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
2064123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
2065123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
2066123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
2067123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
2068923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
2070923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2071bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa    // update sound effect volume
2072bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa    private void updateSoundEffectVolume() {
2073bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        if (mAudioManager == null) {
2074bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2075bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa            if (mAudioManager == null) return;
2076bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        }
2077bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        // This aligns with the current media volume minus 6dB
2078bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        mFxVolume = (float) mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
2079bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa                / (float) mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) / 4.0f;
2080bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa    }
2081bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa
2082923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
2083923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
2084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2085923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2086bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa            if (mAudioManager == null) return;
2087923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2088bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
2089923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2090923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2091923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
2092923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
2093923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
2094923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2095c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            if (mKeyboardSwitcher.getKeyboardView() != null) {
2096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
2097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
209917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (isSoundOn()) {
2100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int sound = AudioManager.FX_KEYPRESS_STANDARD;
2101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
2102571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_DELETE:
2103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_DELETE;
2104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2105571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_ENTER:
2106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_RETURN;
2107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2108571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                case Keyboard.CODE_SPACE:
2109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    sound = AudioManager.FX_KEYPRESS_SPACEBAR;
2110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
2111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2112bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa            mAudioManager.playSoundEffect(sound, mFxVolume);
2113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2116409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
211717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mVibrateOn) {
2118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
2119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2120c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
21211679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null) {
21221679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.performHapticFeedback(
2123979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    HapticFeedbackConstants.KEYBOARD_TAP,
212466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
2125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
212871c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
21299318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        return mWordComposer;
21306516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
21316516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
213217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    boolean isSoundOn() {
213317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSoundOn && !mSilentModeOn;
2134979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2135979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2136e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
21379f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: cleanup messy flags
2138f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
2139c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa                && !mInputTypeNoAutoCorrect;
214017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled)
2141e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
214217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
214317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect
214417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && mSettingsValues.mAutoCorrectEnabled)
2145979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2146e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2147e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2148e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2149e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2150e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
21510ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void updateAutoTextEnabled() {
215232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        if (mSuggest == null) return;
2153f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        // We want to use autotext if the settings are asking for auto corrections, and if
2154f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        // the input language is the same as the system language (because autotext will only
2155f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        // work in the system language so if we are entering text in a different language we
2156f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        // do not want it on).
2157f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        // We used to look at the "quick fixes" option instead of mAutoCorrectEnabled, but
2158f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        // this option was redundant and confusing and therefore removed.
2159f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        mSuggest.setQuickFixesEnabled(mSettingsValues.mAutoCorrectEnabled
21604ab730dbd34fad323063f2ffd31ce33de746668dsatok                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
216132e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
216232e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
216317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) {
21647599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
21659502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2166458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
21677599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2168458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
21697599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
21707599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
21717599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
21727599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
21737599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
21747599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2175466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
2176cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        launchSettingsClass(Settings.class);
2177466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2178466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2179bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
2180cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        launchSettingsClass(DebugSettings.class);
2181bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2182bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2183cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    protected void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) {
2184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2186466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21912fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
219285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
219385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
219485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
219585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
219685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
219785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
219885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
21992fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
22002fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
22012fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
22022fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
220385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
22042cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
22052cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
22062fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
22072fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
22082fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
22092fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2210aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2211aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2212aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
22132fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
22142fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
221585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
2216bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        final AlertDialog.Builder builder = new AlertDialog.Builder(this)
2217bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setItems(items, listener)
2218bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setTitle(title);
2219bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        showOptionDialogInternal(builder.create());
22202fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22222fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
222385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
222485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
222585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
222685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
222785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
222885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
22295a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2232923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
223385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2234ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
22352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
223685996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2237ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
22382fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2239923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
224185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
2242bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        final AlertDialog.Builder builder = new AlertDialog.Builder(this)
2243bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setItems(items, listener)
2244bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setTitle(title);
2245bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        showOptionDialogInternal(builder.create());
2246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22487e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
22497e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2251a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2253923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
22559318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        p.println("  mComposingStringBuilder=" + mComposingStringBuilder.toString());
22569fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
2258f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        p.println("  mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
225917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
22600730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        p.println("  mShouldInsertMagicSpace=" + mShouldInsertMagicSpace);
22611b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
226317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mSoundOn=" + mSettingsValues.mSoundOn);
226417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mVibrateOn=" + mSettingsValues.mVibrateOn);
2265240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        p.println("  mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
2266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
22676e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2269a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2274a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2281923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2286