LatinIME.java revision 644d33d60ea5a87501274488013d65f55238895e
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;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
4166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.view.HapticFeedbackConstants;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.KeyEvent;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
448e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewGroup;
458e09172df1bb176cc899940862c56bed9b9aec4esatokimport android.view.ViewParent;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
48466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport android.view.inputmethod.ExtractedText;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.InputConnection;
50c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka
515ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils;
52c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.CompatUtils;
53c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.EditorInfoCompatUtils;
54c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputConnectionCompatUtils;
55c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
56c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodServiceCompatWrapper;
57c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.compat.InputTypeCompatUtils;
581fef530ec7626fa16777f52b48191e61db8f46d4satokimport com.android.inputmethod.compat.SuggestionSpanUtils;
5928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasaimport com.android.inputmethod.compat.VibratorCompatWrapper;
60c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.LanguageSwitcherProxy;
61c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.deprecated.VoiceProxy;
6283ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasaimport com.android.inputmethod.keyboard.Key;
63c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
64c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
65c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
66f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
67c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboard;
68c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaokaimport com.android.inputmethod.keyboard.LatinKeyboardView;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
70466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
71466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
72466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
73466741d8a78965b8509bf527344f289e50873092Mike LeBeau
74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
77c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaokapublic class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener,
78913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        SuggestionsView.Listener {
798efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    private static final String TAG = LatinIME.class.getSimpleName();
80979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final boolean PERF_DEBUG = false;
81409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
829e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka    private static boolean DEBUG;
83a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
848efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
858efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
868efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
878efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
888efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     *
898efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * @deprecated Use {@link LatinIME#IME_OPTION_NO_MICROPHONE} with package name prefixed.
908efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
9110dd34de0ffcde0104f7d2dae3a3c9fd66abffccsatok    @SuppressWarnings("dep-ann")
928efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE_COMPAT = "nm";
938efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
948efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka    /**
958efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * The private IME option used to indicate that no microphone should be
968efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * shown for a given text field. For instance, this is specified by the
978efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     * search dialog when the dialog is already showing a voice search button.
988efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka     */
994199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_MICROPHONE = "noMicrophoneKey";
1004199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
1014199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    /**
1024199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * The private IME option used to indicate that no settings key should be
1034199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     * shown for a given text field.
1044199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka     */
1054199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey";
1068efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka
107af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka    /**
108af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka     * The private IME option used to indicate that the given text field needs
109af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka     * ASCII code points input.
110af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka     */
111af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka    public static final String IME_OPTION_FORCE_ASCII = "forceAscii";
112af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka
113af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka    /**
114af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka     * The subtype extra value used to indicate that the subtype keyboard layout is capable for
115af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka     * typing ASCII characters.
116af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka     */
117af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka    public static final String SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
118af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka
119d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka    /**
120294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima     * The subtype extra value used to indicate that the subtype keyboard layout supports touch
121294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima     * position correction.
122294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima     */
123294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima    public static final String SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION =
124294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            "SupportTouchPositionCorrection";
125294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima    /**
126d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka     * The subtype extra value used to indicate that the subtype keyboard layout should be loaded
127d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka     * from the specified locale.
128d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka     */
129d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka    public static final String SUBTYPE_EXTRA_VALUE_KEYBOARD_LOCALE = "KeyboardLocale";
130d81479a340d76afaef14ce683322e1488167919cTadashi G. Takaoka
1319e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
132fd0bd57deb53c4cce32810a61133fa44b45dbb7bKen Wakasa
133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // How many continuous deletes at which to start deleting at a higher speed.
134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int DELETE_ACCELERATE_AT = 20;
135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Key events coming any faster than this are long-presses.
136d67fe0e7583f1be18b35b33b7658e4427f1e3dedAmith Yamasani    private static final int QUICK_PRESS = 200;
137a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
13859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    private static final int PENDING_IMS_CALLBACK_DURATION = 800;
139055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
140cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
141cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
142cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
143cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
144cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
145cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1467599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private int mSuggestionVisibility;
1477599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
1487599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_value;
1497599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
1507599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
1517599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
1527599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            = R.string.prefs_suggestion_visibility_hide_value;
1537599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1547599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
1557599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_VALUE,
1567599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
1577599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        SUGGESTION_VISIBILILTY_HIDE_VALUE
1587599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    };
1597599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
160120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // Magic space: a space that should disappear on space/apostrophe insertion, move after the
161120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // punctuation on punctuation insertion, and become a real space on alpha char insertion.
162120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // Weak space: a space that be swapped only by suggestion strip punctuation.
163120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // Double space: the state where the user pressed space twice quickly, which LatinIME
164120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // resolved as period-space. Undoing this converts the period to a space.
165120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // Swap punctuation: the state where a (weak or magic) space and a punctuation from the
166120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // suggestion strip have just been swapped. Undoing this swaps them back.
167120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private static final int SPACE_STATE_NONE = 0;
168120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private static final int SPACE_STATE_DOUBLE = 1;
169120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private static final int SPACE_STATE_SWAP_PUNCTUATION = 2;
170120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private static final int SPACE_STATE_MAGIC = 3;
171120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private static final int SPACE_STATE_WEAK = 4;
172120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard
173120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // Current space state of the input method. This can be any of the above constants.
174120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private int mSpaceState;
175126698fdd256a2e3734634d3b923cabd800064baJean Chalard
17617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private Settings.Values mSettingsValues;
17717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
178d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka    private View mExtractArea;
179abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka    private View mKeyPreviewBackingView;
180913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private View mSuggestionsContainer;
181913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private SuggestionsView mSuggestionsView;
182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Suggest mSuggest;
1831b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private CompletionInfo[] mApplicationSpecifiedCompletions;
184a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
185610f1dc8553cf2ed97e763a06a19380c4a6cd636satok    private InputMethodManagerCompatWrapper mImm;
1862fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private Resources mResources;
1872fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private SharedPreferences mPrefs;
1882fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private String mInputMethodId;
18971c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    private KeyboardSwitcher mKeyboardSwitcher;
1900ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
191b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    private VoiceProxy mVoiceProxy;
192a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private UserDictionary mUserDictionary;
194979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private UserBigramDictionary mUserBigramDictionary;
195f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard    private UserUnigramDictionary mUserUnigramDictionary;
196ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka    private boolean mIsUserDictionaryAvaliable;
19736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1980730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    // TODO: Create an inner class to group options and pseudo-options to improve readability.
199c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // These variables are initialized according to the {@link EditorInfo#inputType}.
20026a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard    private boolean mInsertSpaceOnPickSuggestionManually;
201c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mInputTypeNoAutoCorrect;
202c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mIsSettingsSuggestionStripOn;
203c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    private boolean mApplicationSpecifiedCompletionOn;
204c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
2059318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa    private final StringBuilder mComposingStringBuilder = new StringBuilder();
2069318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa    private WordComposer mWordComposer = new WordComposer();
207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mBestWord;
208f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard    private boolean mHasUncommittedTypedChars;
209409220583333bdf06290dd9fd42f91b5c0d1b11asatok
21079efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCorrectionMode;
21179efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mCommittedLength;
212979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    // Keep track of the last selection range to decide if we need to show word alternatives
21379efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionStart;
21479efbed76f638be298493107fa2d0cd1b5eb529esatok    private int mLastSelectionEnd;
215979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2164733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't
2174733609947c0ec74e460bd714fffca0518ade93aJean Chalard    // "expect" it, it means the user actually moved the cursor.
2184733609947c0ec74e460bd714fffca0518ade93aJean Chalard    private boolean mExpectingUpdateSelection;
219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDeleteCount;
220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastKeyTime;
221a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private AudioManager mAudioManager;
223f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa    private float mFxVolume = -1.0f; // default volume
22417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private boolean mSilentModeOn; // System-wide current configuration
225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
22628f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa    private VibratorCompatWrapper mVibrator;
22728f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa    private long mKeypressVibrationDuration = -1;
22828f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa
229b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok    // TODO: Move this flag to VoiceProxy
23081c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani    private boolean mConfigurationChanging;
231466741d8a78965b8509bf527344f289e50873092Mike LeBeau
23238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    // Member variables for remembering the current device orientation.
23338f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    private int mDisplayOrientation;
23438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
235cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
236cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private BroadcastReceiver mDictionaryPackInstallReceiver =
237cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard            new DictionaryPackInstallBroadcastReceiver(this);
238cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
239dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    // Keeps track of most recently inserted text (multi-character key) for reverting
240dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    private CharSequence mEnteredText;
241dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
242604d80c67185954d4691ac775be59c499eee3b1csatok    private final ComposingStateManager mComposingStateManager =
243fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok            ComposingStateManager.getInstance();
244604d80c67185954d4691ac775be59c499eee3b1csatok
2454f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public final UIHandler mHandler = new UIHandler(this);
246d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
2474f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
248d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTIONS = 0;
24945f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_UPDATE_SHIFT_STATE = 1;
25045f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_VOICE_RESULTS = 2;
25145f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3;
25245f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 4;
25345f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_SPACE_TYPED = 5;
25445f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_SET_BIGRAM_PREDICTIONS = 6;
25545f45a4fdb16d0fa44b4a34b880e5fabb41c1492Jean Chalard        private static final int MSG_PENDING_IMS_CALLBACK = 7;
25638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
2574f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UIHandler(LatinIME outerInstance) {
2584f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
2594f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
2604f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
2634f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinIME latinIme = getOuterInstance();
2644f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
265c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka            final LatinKeyboardView inputView = switcher.getKeyboardView();
266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
267d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTIONS:
2684f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.updateSuggestions();
269d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
270d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
271de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                switcher.updateShiftState();
272d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
273cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            case MSG_SET_BIGRAM_PREDICTIONS:
2744f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.updateBigramPredictions();
27589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                break;
276d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_VOICE_RESULTS:
2774f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                latinIme.mVoiceProxy.handleVoiceResults(latinIme.preferCapitalization()
278de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                        || (switcher.isAlphabetMode() && switcher.isShiftedOrShiftLocked()));
279de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
280de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_FADEOUT_LANGUAGE_ON_SPACEBAR:
28117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
28266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
2834f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            (1.0f + latinIme.mSettingsValues.
2844f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                                    mFinalFadeoutFactorOfLanguageOnSpacebar) / 2,
28566432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                            (LatinKeyboard)msg.obj);
28617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
287de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                sendMessageDelayed(obtainMessage(MSG_DISMISS_LANGUAGE_ON_SPACEBAR, msg.obj),
2884f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        latinIme.mSettingsValues.mDurationOfFadeoutLanguageOnSpacebar);
289de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                break;
290de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            case MSG_DISMISS_LANGUAGE_ON_SPACEBAR:
29117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                if (inputView != null) {
29266432cfc9b7680a653bcf19d0d4250db21155eceTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(
2934f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
29417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                            (LatinKeyboard)msg.obj);
29517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
296d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
299d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
300d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateSuggestions() {
301d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
3029b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS),
3034f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
304d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
305d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
306d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
307d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTIONS);
308d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
309d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
310d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
311d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            return hasMessages(MSG_UPDATE_SUGGESTIONS);
312d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
313d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
314d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void postUpdateShiftKeyState() {
315d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
31617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
3174f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateShiftState);
318d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
319d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
320d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void cancelUpdateShiftState() {
321d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
322d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
323d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
324cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void postUpdateBigramPredictions() {
325cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
3269b2192bfd2d3a06df3c685ed4287e192dbaabf32Ken Wakasa            sendMessageDelayed(obtainMessage(MSG_SET_BIGRAM_PREDICTIONS),
3274f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDelayUpdateSuggestions);
32889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
32989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
330cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        public void cancelUpdateBigramPredictions() {
331cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            removeMessages(MSG_SET_BIGRAM_PREDICTIONS);
33289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
33389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
334d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public void updateVoiceResults() {
335d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
336d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
337de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka
338d5a6b910e83de6dea3c5813cbf5e219abaccdf8aTadashi G. Takaoka        public void startDisplayLanguageOnSpacebar(boolean localeChanged) {
3394f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final LatinIME latinIme = getOuterInstance();
340de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR);
341de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            removeMessages(MSG_DISMISS_LANGUAGE_ON_SPACEBAR);
342c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka            final LatinKeyboardView inputView = latinIme.mKeyboardSwitcher.getKeyboardView();
343de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            if (inputView != null) {
3444f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                final LatinKeyboard keyboard = latinIme.mKeyboardSwitcher.getLatinKeyboard();
345c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The language is always displayed when the delay is negative.
346c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                final boolean needsToDisplayLanguage = localeChanged
3474f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        || latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar < 0;
348de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                // The language is never displayed when the delay is zero.
3494f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                if (latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar != 0) {
350c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                    inputView.setSpacebarTextFadeFactor(needsToDisplayLanguage ? 1.0f
3514f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            : latinIme.mSettingsValues.mFinalFadeoutFactorOfLanguageOnSpacebar,
3524f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            keyboard);
35317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                }
354c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka                // The fadeout animation will start when the delay is positive.
3554f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                if (localeChanged
3564f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                        && latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar > 0) {
357de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_FADEOUT_LANGUAGE_ON_SPACEBAR, keyboard),
3584f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                            latinIme.mSettingsValues.mDelayBeforeFadeoutLanguageOnSpacebar);
359de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka                }
360de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka            }
361de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        }
362fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
363fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void startDoubleSpacesTimer() {
364fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
365fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_SPACE_TYPED),
3664f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                    getOuterInstance().mSettingsValues.mDoubleSpacesTurnIntoPeriodTimeout);
367fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
368fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
369fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public void cancelDoubleSpacesTimer() {
370fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            removeMessages(MSG_SPACE_TYPED);
371fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
372fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka
373fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        public boolean isAcceptingDoubleSpaces() {
374fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            return hasMessages(MSG_SPACE_TYPED);
375fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka        }
37638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
37759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        // Working variables for the following methods.
37859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mIsOrientationChanging;
37959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mPendingSuccesiveImsCallback;
38059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mHasPendingStartInput;
38159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mHasPendingFinishInputView;
38259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mHasPendingFinishInput;
38359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
38459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void startOrientationChanging() {
38559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mIsOrientationChanging = true;
386055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            final LatinIME latinIme = getOuterInstance();
38759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            latinIme.mKeyboardSwitcher.saveKeyboardState();
38859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
38959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
39059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private void resetPendingImsCallback() {
39159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mHasPendingFinishInputView = false;
39259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mHasPendingFinishInput = false;
39359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mHasPendingStartInput = false;
39459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
39559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
39659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private void executePendingImsCallback(LatinIME latinIme, EditorInfo attribute,
39759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                boolean restarting) {
39859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (mHasPendingFinishInputView)
39959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onFinishInputViewInternal(mHasPendingFinishInput);
40059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (mHasPendingFinishInput)
40159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onFinishInputInternal();
40259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (mHasPendingStartInput)
40359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onStartInputInternal(attribute, restarting);
40459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            resetPendingImsCallback();
40559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
40659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
40759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void onStartInput(EditorInfo attribute, boolean restarting) {
40859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
40959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                // Typically this is the second onStartInput after orientation changed.
41059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                mHasPendingStartInput = true;
41159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            } else {
41259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                if (mIsOrientationChanging && restarting) {
41359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                    // This is the first onStartInput after orientation changed.
41459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                    mIsOrientationChanging = false;
41559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                    mPendingSuccesiveImsCallback = true;
41659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                }
41759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                final LatinIME latinIme = getOuterInstance();
41859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                executePendingImsCallback(latinIme, attribute, restarting);
41959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onStartInputInternal(attribute, restarting);
420055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            }
421055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        }
422055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
42359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void onStartInputView(EditorInfo attribute, boolean restarting) {
42459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka             if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
42559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 // Typically this is the second onStartInputView after orientation changed.
42659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 resetPendingImsCallback();
42759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka             } else {
42859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 if (mPendingSuccesiveImsCallback) {
42959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                     // This is the first onStartInputView after orientation changed.
43059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                     mPendingSuccesiveImsCallback = false;
43159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                     resetPendingImsCallback();
43259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                     sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK),
43359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                             PENDING_IMS_CALLBACK_DURATION);
43459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 }
43559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 final LatinIME latinIme = getOuterInstance();
43659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 executePendingImsCallback(latinIme, attribute, restarting);
43759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                 latinIme.onStartInputViewInternal(attribute, restarting);
43859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka             }
43959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
44059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
44159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void onFinishInputView(boolean finishingInput) {
44259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
44359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                // Typically this is the first onFinishInputView after orientation changed.
44459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                mHasPendingFinishInputView = true;
44559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            } else {
44659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                final LatinIME latinIme = getOuterInstance();
44759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onFinishInputViewInternal(finishingInput);
44838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
44938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
450ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka
45159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void onFinishInput() {
45259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
45359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                // Typically this is the first onFinishInput after orientation changed.
45459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                mHasPendingFinishInput = true;
45559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            } else {
45659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                final LatinIME latinIme = getOuterInstance();
45759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                executePendingImsCallback(latinIme, null, false);
45859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onFinishInputInternal();
459ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka            }
460ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka        }
46138f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    }
46238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
4637e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
4647e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
46527d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
46627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mPrefs = prefs;
46727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        LatinImeLogger.init(this, prefs);
4686d9021527a38ba1e94225020389621a0d7227aa1satok        LanguageSwitcherProxy.init(this, prefs);
469bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        InputMethodManagerCompatWrapper.init(this);
470ef5dfc480c7a3e3e34a20b7aacc731942e7a0578Tadashi G. Takaoka        SubtypeSwitcher.init(this);
47127d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        KeyboardSwitcher.init(this, prefs);
4725ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette        AccessibilityUtils.init(this, prefs);
473363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
474923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
475363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
476bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        mImm = InputMethodManagerCompatWrapper.getInstance();
4778efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
4780ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
4790ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
48028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa        mVibrator = VibratorCompatWrapper.getInstance(this);
4819e2d810dc524380ca1db6b384cfb00b4401585e5Tadashi G. Takaoka        DEBUG = LatinImeLogger.sDBG;
482363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
483363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        final Resources res = getResources();
484363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka        mResources = res;
485fd7d814c81132bdd59146a39dd668532f9514cd1Jean Chalard
48628f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa        loadSettings();
48728f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa
4889502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
489979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        boolean tryGC = true;
4909502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
491979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            try {
4920ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                initSuggest();
493979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                tryGC = false;
494979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            } catch (OutOfMemoryError e) {
4959502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
496979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
497979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
498979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
499f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka        mDisplayOrientation = res.getConfiguration().orientation;
500b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
501cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Register to receive ringer mode change and network state change.
502cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        // Also receive installation and removal of a dictionary pack.
503123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
504123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
505123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        registerReceiver(mReceiver, filter);
507b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy = VoiceProxy.init(this, prefs, mHandler);
508cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
509cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final IntentFilter packageFilter = new IntentFilter();
510cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
511cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
512cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        packageFilter.addDataScheme(SCHEME_PACKAGE);
513cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
514646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard
515646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        final IntentFilter newDictFilter = new IntentFilter();
516646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        newDictFilter.addAction(
517646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard                DictionaryPackInstallBroadcastReceiver.NEW_DICTIONARY_INTENT_ACTION);
518646d950ed8d2b2555df92855e18b350fd7761b21Jean Chalard        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
52036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
52117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    // Has to be package-visible for unit tests
52217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    /* package */ void loadSettings() {
52317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
52417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
52517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
52614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
527bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        updateSoundEffectVolume();
52828f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa        updateKeypressVibrationDuration();
52917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    }
53017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
5310ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private void initSuggest() {
532cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
533ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard        final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
53436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
535309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard        final Resources res = mResources;
536ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard        final Locale savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale);
53714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        final ContactsDictionary oldContactsDictionary;
53836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        if (mSuggest != null) {
53914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            oldContactsDictionary = mSuggest.getContactsDictionary();
54036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani            mSuggest.close();
54114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        } else {
54214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            oldContactsDictionary = null;
54336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani        }
544979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5458efc0addce3cd1a32618bf18bafabaaca2b498b0Tadashi G. Takaoka        int mainDicResId = Utils.getMainDictionaryResourceId(res);
546cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest = new Suggest(this, mainDicResId, keyboardLocale);
54717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCorrectEnabled) {
54817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
54917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        }
550e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
551cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mUserDictionary = new UserDictionary(this, localeStr);
552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggest.setUserDictionary(mUserDictionary);
553ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka        mIsUserDictionaryAvaliable = mUserDictionary.isEnabled();
554e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
55514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        resetContactsDictionary(oldContactsDictionary);
556e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
557f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        mUserUnigramDictionary
558f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                = new UserUnigramDictionary(this, this, localeStr, Suggest.DIC_USER_UNIGRAM);
559f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        mSuggest.setUserUnigramDictionary(mUserUnigramDictionary);
560e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
561f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        mUserBigramDictionary
562f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                = new UserBigramDictionary(this, this, localeStr, Suggest.DIC_USER_BIGRAM);
563e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        mSuggest.setUserBigramDictionary(mUserBigramDictionary);
564e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa
565e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        updateCorrectionMode();
56636fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
567ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard        LocaleUtils.setSystemLocale(res, savedLocale);
568923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
56936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
57014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard    /**
57114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * Resets the contacts dictionary in mSuggest according to the user settings.
57214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     *
57314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * This method takes an optional contacts dictionary to use. Since the contacts dictionary
57414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * does not depend on the locale, it can be reused across different instances of Suggest.
57514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * The dictionary will also be opened or closed as necessary depending on the settings.
57614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     *
57714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     * @param oldContactsDictionary an optional dictionary to use, or null
57814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard     */
57914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard    private void resetContactsDictionary(final ContactsDictionary oldContactsDictionary) {
58014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        final boolean shouldSetDictionary = (null != mSuggest && mSettingsValues.mUseContactsDict);
58114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard
58214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        final ContactsDictionary dictionaryToUse;
58314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        if (!shouldSetDictionary) {
58414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // Make sure the dictionary is closed. If it is already closed, this is a no-op,
58514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // so it's safe to call it anyways.
58614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            if (null != oldContactsDictionary) oldContactsDictionary.close();
58714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            dictionaryToUse = null;
58814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        } else if (null != oldContactsDictionary) {
58914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // Make sure the old contacts dictionary is opened. If it is already open, this is a
59014051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            // no-op, so it's safe to call it anyways.
59114051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            oldContactsDictionary.reopen(this);
59214051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            dictionaryToUse = oldContactsDictionary;
59314051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        } else {
59414051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
59514051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        }
59614051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard
59714051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        if (null != mSuggest) {
59814051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard            mSuggest.setContactsDictionary(dictionaryToUse);
59914051e2b5343db4b0531b7b4b806da0c09d6e251Jean Chalard        }
600699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard    }
601699094f9b6e0a4621e8b3cfab70b59c0c7c086bbJean Chalard
602cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /* package private */ void resetSuggestMainDict() {
603cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        final String localeStr = mSubtypeSwitcher.getInputLocaleStr();
604ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard        final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr);
605cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        int mainDicResId = Utils.getMainDictionaryResourceId(mResources);
606cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        mSuggest.resetMainDict(this, mainDicResId, keyboardLocale);
607cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
608cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
609466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
610466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
611e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa        if (mSuggest != null) {
612e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest.close();
613e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa            mSuggest = null;
614979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        unregisterReceiver(mReceiver);
616cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
617b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.destroy();
618979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
619979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.onDestroy();
620923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
621923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
622923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
623923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
624923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onConfigurationChanged(Configuration conf) {
625dc64b138b5e3fb3706c0818d0a308fe6e36985b0Tadashi G. Takaoka        mSubtypeSwitcher.onConfigurationChanged(conf);
626604d80c67185954d4691ac775be59c499eee3b1csatok        mComposingStateManager.onFinishComposingText();
627b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        // If orientation changed while predicting, commit the change
628f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka        if (mDisplayOrientation != conf.orientation) {
629f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka            mDisplayOrientation = conf.orientation;
630f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka            mHandler.startOrientationChanging();
6319351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            final InputConnection ic = getCurrentInputConnection();
632466741d8a78965b8509bf527344f289e50873092Mike LeBeau            commitTyped(ic);
633466741d8a78965b8509bf527344f289e50873092Mike LeBeau            if (ic != null) ic.finishComposingText(); // For voice input
6342fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            if (isShowingOptionDialog())
6352fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                mOptionsDialog.dismiss();
636b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
6378b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
63881c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = true;
639923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
640b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.onConfigurationChanged(conf);
64181c52293f84ce475ac6b1661f4a4b92703405247Amith Yamasani        mConfigurationChanging = false;
64288fc9d44186120f9edc5cf7ec0e2af85260fed04satok
64388fc9d44186120f9edc5cf7ec0e2af85260fed04satok        // This will work only when the subtype is not supported.
64488fc9d44186120f9edc5cf7ec0e2af85260fed04satok        LanguageSwitcherProxy.onConfigurationChanged(conf);
645923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
646b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
647923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
648923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
6496c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView();
6506c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    }
6516c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka
6526c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    @Override
6536c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    public void setInputView(View view) {
6546c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka        super.setInputView(view);
655d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        mExtractArea = getWindow().getWindow().getDecorView()
656d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka                .findViewById(android.R.id.extractArea);
657abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka        mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing);
658913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsContainer = view.findViewById(R.id.suggestions_container);
659913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view);
660913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (mSuggestionsView != null)
661913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionsView.setListener(this, view);
662f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka        if (LatinImeLogger.sVISUALDEBUG) {
663f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka            mKeyPreviewBackingView.setBackgroundColor(0x10FF0000);
664f5fe245df0548ea0a8ec607f2392de0fe02c141dTadashi G. Takaoka        }
665923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
666923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
667923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
668c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    public void setCandidatesView(View view) {
669c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        // To ensure that CandidatesView will never be set.
670c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return;
671923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
673a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
67459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    public void onStartInput(EditorInfo attribute, boolean restarting) {
67559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        mHandler.onStartInput(attribute, restarting);
67659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
67759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
67859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    @Override
679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onStartInputView(EditorInfo attribute, boolean restarting) {
68059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        mHandler.onStartInputView(attribute, restarting);
68159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
68259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
68359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    @Override
68459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    public void onFinishInputView(boolean finishingInput) {
68559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        mHandler.onFinishInputView(finishingInput);
68659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
68738f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
68859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    @Override
68959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    public void onFinishInput() {
69059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        mHandler.onFinishInput();
69159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
69259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
69359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    private void onStartInputInternal(EditorInfo attribute, boolean restarting) {
69459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        super.onStartInput(attribute, restarting);
69559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
69659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
69759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    private void onStartInputViewInternal(EditorInfo attribute, boolean restarting) {
69859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        super.onStartInputView(attribute, restarting);
69945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
700c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka        LatinKeyboardView inputView = switcher.getKeyboardView();
7018e09172df1bb176cc899940862c56bed9b9aec4esatok
70289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (DEBUG) {
703f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka            Log.d(TAG, "onStartInputView: attribute:" + ((attribute == null) ? "none"
704f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka                    : String.format("inputType=0x%08x imeOptions=0x%08x",
705f0f726464dcb5b3cef4f8e703659b35ca62430b5Tadashi G. Takaoka                            attribute.inputType, attribute.imeOptions)));
706910b73127fa207dd26ec8124000262523b0aac0csatok        }
707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
708979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (inputView == null) {
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
712b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        // Forward this event to the accessibility utilities, if enabled.
713b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance();
714b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        if (accessUtils.isTouchExplorationEnabled()) {
715b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette            accessUtils.onStartInputViewInternal(attribute, restarting);
716b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        }
717b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette
7188d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        mSubtypeSwitcher.updateParametersOnStartInputView();
7194ab730dbd34fad323063f2ffd31ce33de746668dsatok
720662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        TextEntryState.reset();
7216c7c8f5b477e7aea207d41417092e8b92db2e24fAmith Yamasani
722055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
723055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        // know now whether this is a password text field, because we need to know now whether we
724055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        // want to enable the voice button.
725055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        final VoiceProxy voiceIme = mVoiceProxy;
7263be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka        final int inputType = (attribute != null) ? attribute.inputType : 0;
7273be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka        voiceIme.resetVoiceStates(InputTypeCompatUtils.isPasswordInputType(inputType)
7283be0039164f5e2060b83d0699e293ffc76384732Tadashi G. Takaoka                || InputTypeCompatUtils.isVisiblePasswordInputType(inputType));
729c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
730b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka        // The EditorInfo might have a flag that affects fullscreen mode.
731b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka        // Note: This call should be done by InputMethodService?
732b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka        updateFullscreenMode();
733cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        initializeInputAttributes(attribute);
734c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
735c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.closing();
736c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mEnteredText = null;
7379318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        mComposingStringBuilder.setLength(0);
738f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
739c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mDeleteCount = 0;
740120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        mSpaceState = SPACE_STATE_NONE;
741c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
74217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
74317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateCorrectionMode();
74417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        updateSuggestionVisibility(mPrefs, mResources);
74517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
74617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSuggest != null && mSettingsValues.mAutoCorrectEnabled) {
74717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold);
74817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard         }
74917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.loadSettings(attribute, mPrefs);
75017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        // This will work only when the subtype is not supported.
75117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        LanguageSwitcherProxy.loadSettings();
75217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
753c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (mSubtypeSwitcher.isKeyboardMode()) {
754255486a5d067469e074f3649b3d2747e7a08aaa2Tadashi G. Takaoka            switcher.loadKeyboard(attribute, mSettingsValues);
755c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        }
756c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
757913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (mSuggestionsView != null)
758913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionsView.clear();
759913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        setSuggestionStripShownInternal(
760913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                isSuggestionsStripVisible(), /* needsInputViewShown */ false);
761c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        // Delay updating suggestions because keyboard input view may not be shown at this point.
762c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        mHandler.postUpdateSuggestions();
763c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
764240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn,
765240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard                mSettingsValues.mKeyPreviewPopupDismissDelay);
766c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        inputView.setProximityCorrectionEnabled(true);
767c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
768055265684bdc049db54c3ec2a7fa5404ff36a608Tadashi G. Takaoka        voiceIme.onStartInputView(inputView.getWindowToken());
769c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
770c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
771c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
772c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
773cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void initializeInputAttributes(EditorInfo attribute) {
774cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        if (attribute == null)
775cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            return;
7764b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        final int inputType = attribute.inputType;
77782c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka        if (inputType == InputType.TYPE_NULL) {
77882c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka            // TODO: We should honor TYPE_NULL specification.
77982c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka            Log.i(TAG, "InputType.TYPE_NULL is specified");
78082c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka        }
78182c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka        final int inputClass = inputType & InputType.TYPE_MASK_CLASS;
782c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
78382c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka        if (inputClass == 0) {
78482c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka            Log.w(TAG, String.format("Unexpected input class: inputType=0x%08x imeOptions=0x%08x",
78582c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka                    inputType, attribute.imeOptions));
78682c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka        }
78782c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka
78826a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard        mInsertSpaceOnPickSuggestionManually = false;
789e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        mInputTypeNoAutoCorrect = false;
7909fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mIsSettingsSuggestionStripOn = false;
7911b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletionOn = false;
7921b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        mApplicationSpecifiedCompletions = null;
793dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
79482c8c2e6c00386ae9925fff68ea77bc448897cbdTadashi G. Takaoka        if (inputClass == InputType.TYPE_CLASS_TEXT) {
795cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            mIsSettingsSuggestionStripOn = true;
796913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            // Make sure that passwords are not displayed in {@link SuggestionsView}.
797e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isPasswordInputType(inputType)
798e9957752bcaad048746c7a57bbd2c0a59e1918a0satok                    || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) {
799cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
800cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
801e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)
802cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
80326a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard                // The point in turning this off is that we don't want to insert a space after
80426a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard                // a name when filling a form: we can't delete trailing spaces when changing fields
80526a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard                mInsertSpaceOnPickSuggestionManually = false;
806cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else {
80726a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard                mInsertSpaceOnPickSuggestionManually = true;
808cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
809e9957752bcaad048746c7a57bbd2c0a59e1918a0satok            if (InputTypeCompatUtils.isEmailVariation(variation)) {
810cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
811cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
812cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
813cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
814cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
815cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            } else if (variation == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
816cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // If it's a browser edit field and auto correct is not ON explicitly, then
817cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                // disable auto correction, but keep suggestions on.
818cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
819e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                    mInputTypeNoAutoCorrect = true;
82036ebae2e8d58d36d3f8dd2f8a2d34c0c06522a8eAmith Yamasani                }
821cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
822cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka
823cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If NO_SUGGESTIONS is set, don't do prediction.
824cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0) {
825cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
826cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
827cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
828cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            // If it's not multiline and the autoCorrect flag is not set, then don't correct
829cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0
830cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                    && (inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == 0) {
831cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mInputTypeNoAutoCorrect = true;
832cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
833cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
834cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mIsSettingsSuggestionStripOn = false;
835cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka                mApplicationSpecifiedCompletionOn = isFullscreenMode();
836cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            }
837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
838923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
841e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    public void onWindowHidden() {
842e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        super.onWindowHidden();
843f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
844e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        if (inputView != null) inputView.closing();
845e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    }
846e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
84759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    private void onFinishInputInternal() {
848923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
849a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
850979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
851979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
852b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.flushVoiceInputLogs(mConfigurationChanging);
853409220583333bdf06290dd9fd42f91b5c0d1b11asatok
854f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
855d024ea605cc6b5b0b9fa1bd838d5b0ebd3901a5dKen Wakasa        if (inputView != null) inputView.closing();
856f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard        if (mUserUnigramDictionary != null) mUserUnigramDictionary.flushPendingWrites();
857979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
858466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
859466741d8a78965b8509bf527344f289e50873092Mike LeBeau
86059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    private void onFinishInputViewInternal(boolean finishingInput) {
8616495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
862055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        mKeyboardSwitcher.onFinishInputView();
863f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
8645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka        if (inputView != null) inputView.cancelAllMessages();
865d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
866d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.cancelUpdateSuggestions();
8676495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
8686495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
8696495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
870466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onUpdateExtractedText(int token, ExtractedText text) {
871466741d8a78965b8509bf527344f289e50873092Mike LeBeau        super.onUpdateExtractedText(token, text);
872b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.showPunctuationHintIfNecessary();
873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
876923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onUpdateSelection(int oldSelStart, int oldSelEnd,
877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int newSelStart, int newSelEnd,
878923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            int candidatesStart, int candidatesEnd) {
879923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
880923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                candidatesStart, candidatesEnd);
881466741d8a78965b8509bf527344f289e50873092Mike LeBeau
882466741d8a78965b8509bf527344f289e50873092Mike LeBeau        if (DEBUG) {
883466741d8a78965b8509bf527344f289e50873092Mike LeBeau            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart
884466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ose=" + oldSelEnd
885025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lss=" + mLastSelectionStart
886025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                    + ", lse=" + mLastSelectionEnd
887466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nss=" + newSelStart
888466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", nse=" + newSelEnd
889466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", cs=" + candidatesStart
890466741d8a78965b8509bf527344f289e50873092Mike LeBeau                    + ", ce=" + candidatesEnd);
891466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
892466741d8a78965b8509bf527344f289e50873092Mike LeBeau
893b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.setCursorAndSelection(newSelEnd, newSelStart);
8944f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
895923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If the current selection in the text view changes, we should
896923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // clear whatever candidate text we have.
897025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean selectionChanged = (newSelStart != candidatesEnd
898025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa                || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart;
899025a5e356ec74dbed7f805a2e43adbb2a35320f8Ken Wakasa        final boolean candidatesCleared = candidatesStart == -1 && candidatesEnd == -1;
9004733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (!mExpectingUpdateSelection) {
901120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            if (SPACE_STATE_WEAK == mSpaceState) {
902120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // Test for no WEAK_SPACE action because there is a race condition that may end up
903120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // in coming here on a normal key press. We set this to NONE because after
904120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // a cursor move, we don't want the suggestion strip to swap the space with the
905120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // newly inserted punctuation.
906120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                mSpaceState = SPACE_STATE_NONE;
907126698fdd256a2e3734634d3b923cabd800064baJean Chalard            }
9084c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard            if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars)
9094c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                    || mVoiceProxy.isVoiceInputHighlighted())
9104c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                    && (selectionChanged || candidatesCleared)) {
9114c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                mComposingStringBuilder.setLength(0);
9124c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                mHasUncommittedTypedChars = false;
9134c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                TextEntryState.reset();
914cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard                updateSuggestions();
9154c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                final InputConnection ic = getCurrentInputConnection();
9164c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                if (ic != null) {
9174c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                    ic.finishComposingText();
9184c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                }
919604d80c67185954d4691ac775be59c499eee3b1csatok                mComposingStateManager.onFinishComposingText();
9204c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                mVoiceProxy.setVoiceInputHighlighted(false);
921cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard            } else if (!mHasUncommittedTypedChars) {
9224c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard                TextEntryState.reset();
923cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard                updateSuggestions();
9244c0fe5719853325e51a8ff0652318e2afdaca97fJean Chalard            }
9254733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
9264733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mExpectingUpdateSelection = false;
927d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
928466741d8a78965b8509bf527344f289e50873092Mike LeBeau
929979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        // Make a note of the cursor position
930979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionStart = newSelStart;
931979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mLastSelectionEnd = newSelEnd;
9327a8dac55278cedd838be325f56b4c52d973c61f5satok    }
9337a8dac55278cedd838be325f56b4c52d973c61f5satok
9347a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setLastSelection(int start, int end) {
9357a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionStart = start;
9367a8dac55278cedd838be325f56b4c52d973c61f5satok        mLastSelectionEnd = end;
937923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
939c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
940c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
941c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
942913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * the suggestions view when this happens, but only if the extracted text
943c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
944c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
945913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * cause the suggestions strip to disappear and re-appear.
946c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
947c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
948c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
949fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard        if (isSuggestionsRequested()) return;
950c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
951c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
952c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
953c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
954c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
955c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
956c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
957913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * implementation hides the suggestions view when a vertical movement
958c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
959c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
960c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
961913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * cause the suggestions strip to disappear and re-appear.
962c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
963c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
964c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedCursorMovement(int dx, int dy) {
965fe5364c825058f6c34c0f42135a5520b77525a28Jean Chalard        if (isSuggestionsRequested()) return;
966c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
967c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
968c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
969c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
970923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
971923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
972979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        LatinImeLogger.commit();
973c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka        mKeyboardSwitcher.onHideWindow();
974979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
975923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
9766e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
9776e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
9786e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
9796e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
980b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
981923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
982923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
983923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
984923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
9851b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
986979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (DEBUG) {
987a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
988bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
989bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
990bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
991bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
992923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
993923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
9941b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn) {
9951b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
9961b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            if (applicationSpecifiedCompletions == null) {
997b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani                clearSuggestions();
998923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return;
999923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1000a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
10017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            SuggestedWords.Builder builder = new SuggestedWords.Builder()
10021b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .setApplicationSpecifiedCompletions(applicationSpecifiedCompletions)
10035238df54ad3f648d09d5288f00b0a9d3c0593832Tadashi G. Takaoka                    .setTypedWordValid(false)
10045238df54ad3f648d09d5288f00b0a9d3c0593832Tadashi G. Takaoka                    .setHasMinimalSuggestion(false);
1005979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // When in fullscreen mode, show completions generated by the application
10067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            setSuggestions(builder.build());
1007923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1008c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            setSuggestionStripShown(true);
1009923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1010923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1011923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1012c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) {
1013913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        // TODO: Modify this if we support suggestions with hard keyboard
1014913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (onEvaluateInputViewShown() && mSuggestionsContainer != null) {
1015913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final boolean shouldShowSuggestions = shown
10167a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
10174b1780fa9571409d65d9797d47949ffafaf0f083Tadashi G. Takaoka            if (isFullscreenMode()) {
1018913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                mSuggestionsContainer.setVisibility(
1019913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                        shouldShowSuggestions ? View.VISIBLE : View.GONE);
10207a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            } else {
1021913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                mSuggestionsContainer.setVisibility(
1022913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                        shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE);
10237a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            }
1024923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1025923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1026a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1027c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private void setSuggestionStripShown(boolean shown) {
1028c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
1029543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    }
1030543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa
1031543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
1032923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void onComputeInsets(InputMethodService.Insets outInsets) {
1033923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
1034f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka        final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
1035913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (inputView == null || mSuggestionsContainer == null)
103646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
1037d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        // In fullscreen mode, the height of the extract area managed by InputMethodService should
1038d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        // be considered.
1039d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}.
1040d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0;
1041abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka        final int backingHeight = (mKeyPreviewBackingView.getVisibility() == View.GONE) ? 0
1042abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka                : mKeyPreviewBackingView.getHeight();
104359010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka        final int suggestionsHeight = (mSuggestionsContainer.getVisibility() == View.GONE) ? 0
104459010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka                : mSuggestionsContainer.getHeight();
1045d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        final int extraHeight = extractHeight + backingHeight + suggestionsHeight;
1046abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka        int touchY = extraHeight;
10479e347d3d448e48229c46aad394ec9bd60cd5807bsatok        // Need to set touchable region only if input view is being shown
104846ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        if (mKeyboardSwitcher.isInputViewShown()) {
1049913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (mSuggestionsContainer.getVisibility() == View.VISIBLE) {
105059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka                touchY -= suggestionsHeight;
10519e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
10527a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            final int touchWidth = inputView.getWidth();
1053abb0c77af15a22b5d0953e477da8747cd5f2259dTadashi G. Takaoka            final int touchHeight = inputView.getHeight() + extraHeight
10547a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
10557a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
10569e347d3d448e48229c46aad394ec9bd60cd5807bsatok            if (DEBUG) {
10577a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
10587a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                        + " height=" + touchHeight);
10599e347d3d448e48229c46aad394ec9bd60cd5807bsatok            }
10607a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka            setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
10619e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
106246ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.contentTopInsets = touchY;
106346ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka        outInsets.visibleTopInsets = touchY;
1064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1065a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1066923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
1067979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
1068d874ac581e7f9bb6b93918390aa56fb02d1b66e8Tadashi G. Takaoka        return super.onEvaluateFullscreenMode()
1069d874ac581e7f9bb6b93918390aa56fb02d1b66e8Tadashi G. Takaoka                && mResources.getBoolean(R.bool.config_use_fullscreen_mode);
107059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka    }
107159010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka
107259010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka    @Override
107359010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka    public void updateFullscreenMode() {
107459010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka        super.updateFullscreenMode();
1075f80b6a06992ae08ca3601f4fbc6da550fd9ac730Tadashi G. Takaoka
107659010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka        if (mKeyPreviewBackingView == null) return;
1077d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        // In extract mode, no need to have extra space to show the key preview.
107859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka        // If not, we should have extra space above the keyboard to show the key preview.
1079d44647e76f286256515ddac8cfc1ab29a2cbcf82Tadashi G. Takaoka        mKeyPreviewBackingView.setVisibility(isExtractViewShown() ? View.GONE : View.VISIBLE);
1080979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1081979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1082979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    @Override
1083923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyDown(int keyCode, KeyEvent event) {
1084923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
1085e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_BACK:
10862cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka            if (event.getRepeatCount() == 0) {
10872cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka                if (mSuggestionsView != null && mSuggestionsView.handleBack()) {
10882cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka                    return true;
10892cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka                }
10902cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka                final LatinKeyboardView keyboardView = mKeyboardSwitcher.getKeyboardView();
10912cb36637f41418e4037023a47915dd64a30ab869Tadashi G. Takaoka                if (keyboardView != null && keyboardView.handleBack()) {
10926e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                    return true;
10936e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani                }
1094e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
1095e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
1096923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1097923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyDown(keyCode, event);
1098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
1101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onKeyUp(int keyCode, KeyEvent event) {
1102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (keyCode) {
1103e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_DOWN:
1104e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_UP:
1105e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_LEFT:
1106e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        case KeyEvent.KEYCODE_DPAD_RIGHT:
1107e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            // Enable shift key and DPAD to do selections
1108e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (mKeyboardSwitcher.isInputViewShown()
1109e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
1110e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                KeyEvent newEvent = new KeyEvent(event.getDownTime(), event.getEventTime(),
1111e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getAction(), event.getKeyCode(), event.getRepeatCount(),
1112e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        event.getDeviceId(), event.getScanCode(),
1113e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                        KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON);
11149351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                final InputConnection ic = getCurrentInputConnection();
1115e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                if (ic != null)
1116e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                    ic.sendKeyEvent(newEvent);
1117e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                return true;
1118e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            }
1119e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            break;
1120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return super.onKeyUp(keyCode, event);
1122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11249351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    public void commitTyped(final InputConnection ic) {
11258558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        if (!mHasUncommittedTypedChars) return;
11268558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        mHasUncommittedTypedChars = false;
11278558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        if (mComposingStringBuilder.length() > 0) {
11289351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            if (ic != null) {
11299351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                ic.commitText(mComposingStringBuilder, 1);
1130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
11318558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            mCommittedLength = mComposingStringBuilder.length();
11328558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.acceptedTyped(mComposingStringBuilder);
1133f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            addToUserUnigramAndBigramDictionaries(mComposingStringBuilder,
1134f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                    UserUnigramDictionary.FREQUENCY_FOR_TYPED);
1135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
11368558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        updateSuggestions();
1137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1139b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public boolean getCurrentAutoCapsState() {
11409351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
11411c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        EditorInfo ei = getCurrentInputEditorInfo();
114217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (mSettingsValues.mAutoCap && ic != null && ei != null
114317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && ei.inputType != InputType.TYPE_NULL) {
1144b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return ic.getCursorCapsMode(ei.inputType) != 0;
11451c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        }
1146b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
11471c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
11481c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
1149b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard    // "ic" may be null
1150b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard    private void swapSwapperAndSpaceWhileInBatchEdit(final InputConnection ic) {
1151b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard        if (null == ic) return;
1152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
1153863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        // It is guaranteed lastTwo.charAt(1) is a swapper - else this method is not called.
1154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastTwo != null && lastTwo.length() == 2
1155863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard                && lastTwo.charAt(0) == Keyboard.CODE_SPACE) {
1156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(lastTwo.charAt(1) + " ", 1);
1158b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
11594ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        }
11604ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa    }
11614ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1162120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private boolean maybeDoubleSpaceWhileInBatchEdit(final InputConnection ic) {
1163120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (mCorrectionMode == Suggest.CORRECTION_NONE) return false;
1164120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (ic == null) return false;
11652b4eabed2bfe982b91a994c145401d98894e6ef5Jean Chalard        final CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
1166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (lastThree != null && lastThree.length() == 3
11679351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                && Utils.canBeFollowedByPeriod(lastThree.charAt(0))
1168571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastThree.charAt(1) == Keyboard.CODE_SPACE
1169fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && lastThree.charAt(2) == Keyboard.CODE_SPACE
1170fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka                && mHandler.isAcceptingDoubleSpaces()) {
1171fc20f2198d6703d65eab22f40f9b8aa2c8e3a0eaTadashi G. Takaoka            mHandler.cancelDoubleSpacesTimer();
1172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.deleteSurroundingText(2, 0);
1173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.commitText(". ", 1);
1174b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
1175120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            return true;
1176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1177120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        return false;
1178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1179a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1180b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard    // "ic" must not be null
11819351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) {
118241a519729505a877844f2c57a33509c302dddbceKen Wakasa        // When the text's first character is '.', remove the previous period
118341a519729505a877844f2c57a33509c302dddbceKen Wakasa        // if there is one.
1184b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard        final CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
11854ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa        if (lastOne != null && lastOne.length() == 1
1186571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
1187571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && text.charAt(0) == Keyboard.CODE_PERIOD) {
118841a519729505a877844f2c57a33509c302dddbceKen Wakasa            ic.deleteSurroundingText(1, 0);
118941a519729505a877844f2c57a33509c302dddbceKen Wakasa        }
119041a519729505a877844f2c57a33509c302dddbceKen Wakasa    }
119141a519729505a877844f2c57a33509c302dddbceKen Wakasa
1192b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard    // "ic" may be null
1193b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard    private void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) {
11949a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic == null) return;
1195b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard        final CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
11969a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (lastOne != null && lastOne.length() == 1
1197571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
11989a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.deleteSurroundingText(1, 0);
11999a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
12009a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa    }
12019a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa
1202c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
1203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean addWordToDictionary(String word) {
1204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mUserDictionary.addWord(word, 128);
12056558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // Suggestion strip should be updated after the operation of adding word to the
12066558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        // user dictionary
1207d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateSuggestions();
1208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
1209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean isAlphabet(int code) {
1212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (Character.isLetter(code)) {
1213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
1214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return false;
1216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1218a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1219e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka    private void onSettingsKeyPressed() {
1220cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        if (isShowingOptionDialog()) return;
1221d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
1222d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            showSubtypeSelectorAndSettings();
122311b7febc0bea46a6afb30d7fa040b841eadd7410Ken Wakasa        } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, false /* exclude aux subtypes */)) {
1224d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            showOptionsMenu();
1225d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka        } else {
1226d794c6f0788a65a4ec623de3f8f05122621d665fTadashi G. Takaoka            launchSettings();
12279a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
12289a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
12299a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1230cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    // Virtual codes representing custom requests.  These are used in onCustomRequest() below.
1231cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1;
1232d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka    public static final int CODE_HAPTIC_AND_AUDIO_FEEDBACK = 2;
1233cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa
1234cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    @Override
1235cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    public boolean onCustomRequest(int requestCode) {
1236cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        if (isShowingOptionDialog()) return false;
1237cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        switch (requestCode) {
1238cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        case CODE_SHOW_INPUT_METHOD_PICKER:
123911b7febc0bea46a6afb30d7fa040b841eadd7410Ken Wakasa            if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, true /* include aux subtypes */)) {
124079efbed76f638be298493107fa2d0cd1b5eb529esatok                mImm.showInputMethodPicker();
1241cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa                return true;
12429a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
1243cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa            return false;
1244d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka        case CODE_HAPTIC_AND_AUDIO_FEEDBACK:
1245d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka            hapticAndAudioFeedback(Keyboard.CODE_UNSPECIFIED);
1246d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka            return true;
12479a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
1248cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        return false;
12499a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
12509a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
12519a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
12529a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
12539a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
12549a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1255120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private void insertPunctuationFromSuggestionStrip(final InputConnection ic, final int code) {
1256120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        final CharSequence beforeText = ic != null ? ic.getTextBeforeCursor(1, 0) : null;
1257120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        final int toLeft = TextUtils.isEmpty(beforeText) ? 0 : beforeText.charAt(0);
1258120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        final boolean shouldRegisterSwapPunctuation;
1259120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // If we have a space left of the cursor and it's a weak or a magic space, then we should
1260120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // swap it, and override the space state with SPACESTATE_SWAP_PUNCTUATION.
1261120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // To swap it, we fool handleSeparator to think the previous space state was a
1262120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // magic space.
1263120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (Keyboard.CODE_SPACE == toLeft && mSpaceState == SPACE_STATE_WEAK) {
1264120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            mSpaceState = SPACE_STATE_MAGIC;
1265120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            shouldRegisterSwapPunctuation = true;
1266120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        } else {
1267120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            shouldRegisterSwapPunctuation = false;
1268120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        }
1269120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        onCodeInput(code, new int[] { code },
1270120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                KeyboardActionListener.NOT_A_TOUCH_COORDINATE,
1271120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                KeyboardActionListener.NOT_A_TOUCH_COORDINATE);
1272120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (shouldRegisterSwapPunctuation) {
1273120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
1274120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        }
1275126698fdd256a2e3734634d3b923cabd800064baJean Chalard    }
1276126698fdd256a2e3734634d3b923cabd800064baJean Chalard
12775f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
12785a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
12798aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
1280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long when = SystemClock.uptimeMillis();
1281571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
1282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mDeleteCount = 0;
1283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastKeyTime = when;
1285b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
1286b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
1287120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // The space state depends only on the last character pressed and its own previous
1288120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // state. Here, we revert the space state to neutral if the key is actually modifying
1289120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // the input contents (any non-shift key), which is what we should do for
1290120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // all inputs that do not result in a special state. Each character handling is then
1291120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // free to override the state as they see fit.
1292120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        final int spaceState = mSpaceState;
1293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (primaryCode) {
1294571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_DELETE:
1295120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            mSpaceState = SPACE_STATE_NONE;
1296120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            handleBackspace(spaceState);
12974189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            mDeleteCount++;
12984733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
12994189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            LatinImeLogger.logOnDelete();
13004189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1301571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_SHIFT:
13024189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Shift key is handled in onPress() when device has distinct multi-touch panel.
1303101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1304b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.toggleShift();
13054189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1306e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
13074189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
1308101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!distinctMultiTouch)
1309b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                switcher.changeKeyboardMode();
13104189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1311571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CANCEL:
13124189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            if (!isShowingOptionDialog()) {
13134189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka                handleClose();
13144189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
13154189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1316e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        case Keyboard.CODE_SETTINGS:
1317e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka            onSettingsKeyPressed();
13184189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1319571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_CAPSLOCK:
1320b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            switcher.toggleCapsLock();
1321d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka            hapticAndAudioFeedback(primaryCode);
13224189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1323d2c5fdda862f6dd2a1e020cf674c35fbbc63fc92Tadashi G. Takaoka        case Keyboard.CODE_SHORTCUT:
132420cdb37bd062ae6cb6d42ad6229a19733476cd55satok            mSubtypeSwitcher.switchToShortcutIME();
13254189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
1326571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        case Keyboard.CODE_TAB:
132745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            handleTab();
13284733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // There are two cases for tab. Either we send a "next" event, that may change the
13294733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // focus but will never move the cursor. Or, we send a real tab keycode, which some
13304733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // applications may accept or ignore, and we don't know whether this will move the
13314733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // cursor or not. So actually, we don't really know.
13324733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // So to go with the safer option, we'd rather behave as if the user moved the
13334733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // cursor when they didn't than the opposite. We also expect that most applications
13344733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // will actually use tab only for focus movement.
13354733609947c0ec74e460bd714fffca0518ade93aJean Chalard            // To sum it up: do not update mExpectingUpdateSelection here.
13364189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            break;
13374189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka        default:
1338120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            mSpaceState = SPACE_STATE_NONE;
133917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isWordSeparator(primaryCode)) {
1340120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                handleSeparator(primaryCode, x, y, spaceState);
13414189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            } else {
1342120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                handleCharacter(primaryCode, keyCodes, x, y, spaceState);
13434189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka            }
13444733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
13454733609947c0ec74e460bd714fffca0518ade93aJean Chalard            break;
1346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1347b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.onKey(primaryCode);
1348dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        // Reset after any single keystroke
1349dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = null;
1350923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1351a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
13525a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
13538aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onTextInput(CharSequence text) {
1354b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.commitVoiceInput();
13559351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
1356923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return;
1357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.beginBatchEdit();
135855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        commitTyped(ic);
13599351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        maybeRemovePreviousPeriod(ic, text);
1360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.commitText(text, 1);
1361923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        ic.endBatchEdit();
1362b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
13635f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onKey(Keyboard.CODE_DUMMY);
1364120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        mSpaceState = SPACE_STATE_NONE;
1365dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        mEnteredText = text;
1366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
13685a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
13698aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
137083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
13715f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        mKeyboardSwitcher.onCancelInput();
137283e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
137383e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1374120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private void handleBackspace(final int spaceState) {
1375b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        if (mVoiceProxy.logAndRevertVoiceInput()) return;
13764f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1377504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1378504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (ic == null) return;
1379979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.beginBatchEdit();
1380979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1381b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleBackspace();
13824f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
13839ae24750f462cbd94b362fe54a952c86cfb05e5fKen Wakasa        final boolean deleteChar = !mHasUncommittedTypedChars;
1384f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
13859318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            final int length = mComposingStringBuilder.length();
1386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (length > 0) {
13879318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mComposingStringBuilder.delete(length - 1, length);
13889318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mWordComposer.deleteLast();
1389604d80c67185954d4691ac775be59c499eee3b1csatok                final CharSequence textWithUnderline =
1390604d80c67185954d4691ac775be59c499eee3b1csatok                        mComposingStateManager.isAutoCorrectionIndicatorOn()
1391604d80c67185954d4691ac775be59c499eee3b1csatok                                ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
1392604d80c67185954d4691ac775be59c499eee3b1csatok                                            this, mComposingStringBuilder)
1393604d80c67185954d4691ac775be59c499eee3b1csatok                                : mComposingStringBuilder;
1394604d80c67185954d4691ac775be59c499eee3b1csatok                ic.setComposingText(textWithUnderline, 1);
13959318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                if (mComposingStringBuilder.length() == 0) {
1396f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                    mHasUncommittedTypedChars = false;
1397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
139889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                if (1 == length) {
139989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // 1 == length means we are about to erase the last character of the word,
140089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // so we can show bigrams.
1401cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                    mHandler.postUpdateBigramPredictions();
140289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                } else {
140389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    // length > 1, so we still have letters to deduce a suggestion from.
140489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                    mHandler.postUpdateSuggestions();
140589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                }
1406923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                ic.deleteSurroundingText(1, 0);
1408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1410d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        mHandler.postUpdateShiftKeyState();
1411504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1412120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // TODO: Merge space state with TextEntryState
1413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        TextEntryState.backspace();
1414662bb7c26cadd5026cb3d4e5d081aae163bd5a3aTadashi G. Takaoka        if (TextEntryState.isUndoCommit()) {
14159351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            revertLastWord(ic);
1416979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            ic.endBatchEdit();
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1418504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        }
1419120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (SPACE_STATE_DOUBLE == spaceState) {
14209351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            if (revertDoubleSpace(ic)) {
14219351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                ic.endBatchEdit();
1422120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // No need to reset mSpaceState, it has already be done (that's why we
1423120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // receive it as a parameter)
1424120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                return;
1425120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            }
1426120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        } else if (SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
1427120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            if (revertSwapPunctuation(ic)) {
1428120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                ic.endBatchEdit();
1429120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                // Likewise
14309351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                return;
14314733609947c0ec74e460bd714fffca0518ade93aJean Chalard            }
14324733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
1433504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka
1434504e8d5171edae36ec464a5e0c72cee22bb9ac4dTadashi G. Takaoka        if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
1435dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani            ic.deleteSurroundingText(mEnteredText.length(), 0);
1436923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else if (deleteChar) {
1437913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) {
14386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // Go back to the suggestion mode if the user canceled the
143955b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa                // "Touch again to save".
14406558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // NOTE: In gerenal, we don't revert the word when backspacing
14416558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // from a manual suggestion pick.  We deliberately chose a
14426558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // different behavior only in the case of picking the first
14436558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // suggestion (typed word).  It's intentional to have made this
14446558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                // inconsistent with backspacing after selecting other suggestions.
14459351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                revertLastWord(ic);
14466558253160e2039c87f424bd814f402ecd31de3bKen Wakasa            } else {
1447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
14486558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                if (mDeleteCount > DELETE_ACCELERATE_AT) {
14496558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                    sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
14506558253160e2039c87f424bd814f402ecd31de3bKen Wakasa                }
1451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1453979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        ic.endBatchEdit();
1454923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1455923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
145645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    private void handleTab() {
145745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
1458b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
1459b2707856aba4fc9b063f26305f1fb603b19c1701satok                && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
146045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
146145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
146245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
146345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
146445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
146545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (ic == null)
146645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            return;
146745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
146845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        // True if keyboard is in either chording shift or manual temporary upper case mode.
146945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
1470b2707856aba4fc9b063f26305f1fb603b19c1701satok        if (EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
147145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && !isManualTemporaryUpperCase) {
1472b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionNext(ic);
1473b2707856aba4fc9b063f26305f1fb603b19c1701satok        } else if (EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)
147445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                && isManualTemporaryUpperCase) {
1475b2707856aba4fc9b063f26305f1fb603b19c1701satok            EditorInfoCompatUtils.performEditorActionPrevious(ic);
147645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        }
147745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka    }
147845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka
1479120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x,
1480120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            final int y, final int spaceState) {
1481b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleCharacter();
14824f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
1483b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard        final InputConnection ic = getCurrentInputConnection();
1484b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard        if (ic != null) ic.beginBatchEdit();
1485120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (SPACE_STATE_MAGIC == spaceState
1486126698fdd256a2e3734634d3b923cabd800064baJean Chalard                && mSettingsValues.isMagicSpaceStripper(primaryCode)) {
1487b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard            removeTrailingSpaceWhileInBatchEdit(ic);
14880730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        }
14890730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard
1490e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int code = primaryCode;
14913889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa        if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code))
14923889462439357fd76c0b82dfd52e1ca6e0bafd2dKen Wakasa                && isSuggestionsRequested() && !isCursorTouchingWord()) {
1493f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard            if (!mHasUncommittedTypedChars) {
1494f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard                mHasUncommittedTypedChars = true;
14959318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mComposingStringBuilder.setLength(0);
14969318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                mWordComposer.reset();
14977e99a28dfcc14f5b19220442db972ca8d786b4feKen Wakasa                clearSuggestions();
1498604d80c67185954d4691ac775be59c499eee3b1csatok                mComposingStateManager.onFinishComposingText();
1499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
150135f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
1502f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (switcher.isShiftedOrShiftLocked()) {
1503eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
1504eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                    || keyCodes[0] > Character.MAX_CODE_POINT) {
1505b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard                if (null != ic) ic.endBatchEdit();
1506eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani                return;
1507eef539c3f2b60af74a3ce05ac68288e7f86709aeAmith Yamasani            }
1508e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            code = keyCodes[0];
1509e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (switcher.isAlphabetMode() && Character.isLowerCase(code)) {
151035f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                // In some locales, such as Turkish, Character.toUpperCase() may return a wrong
151135f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                // character because it doesn't take care of locale.
151235f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                final String upperCaseString = new String(new int[] {code}, 0, 1)
151335f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                        .toUpperCase(mSubtypeSwitcher.getInputLocale());
151435f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                if (upperCaseString.codePointCount(0, upperCaseString.length()) == 1) {
151535f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                    code = upperCaseString.codePointAt(0);
151612a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                } else {
151712a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    // Some keys, such as [eszett], have upper case as multi-characters.
151835f20916e5348d7fa485ba8eb0a5cf2e67f4f354Tadashi G. Takaoka                    onTextInput(upperCaseString);
1519b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard                    if (null != ic) ic.endBatchEdit();
152012a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                    return;
152112a4e08a6440c95f29dc04efe83515a4ed045487Tadashi G. Takaoka                }
1522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
1523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1524f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
15259318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mComposingStringBuilder.append((char) code);
15269318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mWordComposer.add(code, keyCodes, x, y);
1527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
15281c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                // If it's the first letter, make note of auto-caps state
15299318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                if (mWordComposer.size() == 1) {
15309318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                    mWordComposer.setAutoCapitalized(getCurrentAutoCapsState());
1531604d80c67185954d4691ac775be59c499eee3b1csatok                    mComposingStateManager.onStartComposingText();
15321c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani                }
1533604d80c67185954d4691ac775be59c499eee3b1csatok                final CharSequence textWithUnderline =
1534604d80c67185954d4691ac775be59c499eee3b1csatok                        mComposingStateManager.isAutoCorrectionIndicatorOn()
1535604d80c67185954d4691ac775be59c499eee3b1csatok                                ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
1536604d80c67185954d4691ac775be59c499eee3b1csatok                                        this, mComposingStringBuilder)
1537604d80c67185954d4691ac775be59c499eee3b1csatok                                : mComposingStringBuilder;
1538604d80c67185954d4691ac775be59c499eee3b1csatok                ic.setComposingText(textWithUnderline, 1);
1539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1540d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
1541923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1542e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            sendKeyChar((char)code);
1543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1544120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (SPACE_STATE_MAGIC == spaceState
1545126698fdd256a2e3734634d3b923cabd800064baJean Chalard                && mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1546b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard            if (null != ic) swapSwapperAndSpaceWhileInBatchEdit(ic);
1547863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1548863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1549b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        switcher.updateShiftState();
1550979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (LatinIME.PERF_DEBUG) measureCps();
155117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y);
1552b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard        if (null != ic) ic.endBatchEdit();
1553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1555120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private void handleSeparator(final int primaryCode, final int x, final int y,
1556120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            final int spaceState) {
1557b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleSeparator();
1558604d80c67185954d4691ac775be59c499eee3b1csatok        mComposingStateManager.onFinishComposingText();
15594f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
156055b10796522b871c1e04d6f2254fdff5dc7aced4Ken Wakasa        // Should dismiss the "Touch again to save" message when handling separator
1561913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) {
1562cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            mHandler.cancelUpdateBigramPredictions();
1563d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
15646558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        }
15656558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
1566923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        boolean pickedDefault = false;
1567923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Handle separator
15681b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        final InputConnection ic = getCurrentInputConnection();
1569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1570923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.beginBatchEdit();
1571923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1572f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (mHasUncommittedTypedChars) {
1573923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // In certain languages where single quote is a separator, it's better
1574a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker            // not to auto correct, but accept the typed word. For instance,
1575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // in Italian dov' should not be expanded to dove' because the elision
1576923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // requires the last vowel to be removed.
1577f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard            final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
1578c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa                    && !mInputTypeNoAutoCorrect;
157917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) {
1580b5d17e52fcda39d540822e615bfb7ed5074e0034satok                pickedDefault = pickDefaultSuggestion(primaryCode);
1581923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1582923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                commitTyped(ic);
1583923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
15854ca6d9dc09cf7635c9283e42f155957021b9f9acKen Wakasa
1586120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        final boolean swapMagicSpace;
1587120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (SPACE_STATE_MAGIC == spaceState) {
158817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard            if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
1589120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                swapMagicSpace = true;
1590863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            } else {
1591120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                swapMagicSpace = false;
1592b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard                if (mSettingsValues.isMagicSpaceStripper(primaryCode)) {
1593b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard                    removeTrailingSpaceWhileInBatchEdit(ic);
1594b715299125e8fbaaa941d994217baf823e6c4013Jean Chalard                }
1595863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            }
15960730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        } else {
1597120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            swapMagicSpace = false;
1598863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard        }
1599863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard
1600120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        sendKeyChar((char)primaryCode);
160189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
160289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (Keyboard.CODE_SPACE == primaryCode) {
1603120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            if (isSuggestionsRequested()) {
1604120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                if (maybeDoubleSpaceWhileInBatchEdit(ic)) {
1605120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                    mSpaceState = SPACE_STATE_DOUBLE;
1606120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                } else if (!isShowingPunctuationList()) {
1607120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                    mSpaceState = SPACE_STATE_WEAK;
1608120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                }
1609126698fdd256a2e3734634d3b923cabd800064baJean Chalard            }
1610120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard
1611120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            mHandler.startDoubleSpacesTimer();
161289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isCursorTouchingWord()) {
161389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard                mHandler.cancelUpdateSuggestions();
1614cb3320179d39a7983874697a0aa428b127675c9dJean Chalard                mHandler.postUpdateBigramPredictions();
161589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            }
161689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
1617120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            if (swapMagicSpace) {
1618120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                swapSwapperAndSpaceWhileInBatchEdit(ic);
1619120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                mSpaceState = SPACE_STATE_MAGIC;
1620120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            }
1621120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard
162289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Set punctuation right away. onUpdateSelection will fire but tests whether it is
162389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // already displayed or not, so it's okay.
162455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            setPunctuationSuggestions();
1625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1626120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard
1627120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        TextEntryState.typedCharacter((char) primaryCode, true, x, y);
1628120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard
1629120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (pickedDefault) {
1630120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            CharSequence typedWord = mWordComposer.getTypedWord();
1631120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            TextEntryState.backToAcceptedDefault(typedWord);
1632120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
1633120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                InputConnectionCompatUtils.commitCorrection(
1634120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard                        ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord);
1635120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            }
1636120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        }
1637b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
1638923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
1639923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            ic.endBatchEdit();
1640923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1641923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1642466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1643923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void handleClose() {
1644923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        commitTyped(getCurrentInputConnection());
1645b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok        mVoiceProxy.handleClose();
1646923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestHideSelf(0);
1647c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka        LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
16481679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        if (inputView != null)
16491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            inputView.closing();
1650923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1651923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
16527a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isSuggestionsRequested() {
1653c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        return mIsSettingsSuggestionStripOn
1654c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka                && (mCorrectionMode > 0 || isShowingSuggestionsStrip());
1655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1656a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
16577a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingPunctuationList() {
1658cb8cb95d0afd340de9f1a0e15948f0068d2450bcKen Wakasa        if (mSuggestionsView == null) return false;
1659913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        return mSettingsValues.mSuggestPuncList == mSuggestionsView.getSuggestions();
16607599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
16617599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
16627a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isShowingSuggestionsStrip() {
16637599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
16647599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
166538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka                        && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT);
16667599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
16677599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
1668913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    public boolean isSuggestionsStripVisible() {
1669913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (mSuggestionsView == null)
1670b5e00d5841b946de8970875231456228ae0eb6b1Ken Wakasa            return false;
1671d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard        if (mSuggestionsView.isShowingAddToDictionaryHint())
16729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
16739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (!isShowingSuggestionsStrip())
16749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return false;
16759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn)
16769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            return true;
16779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        return isSuggestionsRequested();
1678923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1680409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void switchToKeyboardView() {
1681060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (DEBUG) {
1682060efb6d82af1f896d90cb845c8ae07c726f85e1satok            Log.d(TAG, "Switch to keyboard view.");
1683060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1684c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        View v = mKeyboardSwitcher.getKeyboardView();
1685060efb6d82af1f896d90cb845c8ae07c726f85e1satok        if (v != null) {
1686060efb6d82af1f896d90cb845c8ae07c726f85e1satok            // Confirms that the keyboard view doesn't have parent view.
1687060efb6d82af1f896d90cb845c8ae07c726f85e1satok            ViewParent p = v.getParent();
1688060efb6d82af1f896d90cb845c8ae07c726f85e1satok            if (p != null && p instanceof ViewGroup) {
1689060efb6d82af1f896d90cb845c8ae07c726f85e1satok                ((ViewGroup) p).removeView(v);
16905a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            }
1691060efb6d82af1f896d90cb845c8ae07c726f85e1satok            setInputView(v);
1692060efb6d82af1f896d90cb845c8ae07c726f85e1satok        }
1693913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        setSuggestionStripShown(isSuggestionsStripVisible());
1694060efb6d82af1f896d90cb845c8ae07c726f85e1satok        updateInputViewShown();
1695060efb6d82af1f896d90cb845c8ae07c726f85e1satok        mHandler.postUpdateSuggestions();
1696466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1697466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1698409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void clearSuggestions() {
16997e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(SuggestedWords.EMPTY);
1700466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1701466741d8a78965b8509bf527344f289e50873092Mike LeBeau
17027e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords words) {
1703913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        if (mSuggestionsView != null) {
1704913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionsView.setSuggestions(words);
17055e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka            mKeyboardSwitcher.onAutoCorrectionStateChanged(
17065e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka                    words.hasWordAboveAutoCorrectionScoreThreshold());
1707466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1708ec780e2868962bf17f0dfd35d36895f543bde40asatok
1709ec780e2868962bf17f0dfd35d36895f543bde40asatok        // Put a blue underline to a word in TextView which will be auto-corrected.
1710ec780e2868962bf17f0dfd35d36895f543bde40asatok        final InputConnection ic = getCurrentInputConnection();
1711604d80c67185954d4691ac775be59c499eee3b1csatok        if (ic != null) {
1712604d80c67185954d4691ac775be59c499eee3b1csatok            final boolean oldAutoCorrectionIndicator =
1713604d80c67185954d4691ac775be59c499eee3b1csatok                    mComposingStateManager.isAutoCorrectionIndicatorOn();
1714604d80c67185954d4691ac775be59c499eee3b1csatok            final boolean newAutoCorrectionIndicator = Utils.willAutoCorrect(words);
1715604d80c67185954d4691ac775be59c499eee3b1csatok            if (oldAutoCorrectionIndicator != newAutoCorrectionIndicator) {
1716fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok                if (LatinImeLogger.sDBG) {
1717fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok                    Log.d(TAG, "Flip the indicator. " + oldAutoCorrectionIndicator
1718fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok                            + " -> " + newAutoCorrectionIndicator);
1719fe2d90798ea409ee39d6f63942eb01bb7eed98e3satok                }
1720604d80c67185954d4691ac775be59c499eee3b1csatok                final CharSequence textWithUnderline = newAutoCorrectionIndicator
1721604d80c67185954d4691ac775be59c499eee3b1csatok                        ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(
1722604d80c67185954d4691ac775be59c499eee3b1csatok                                this, mComposingStringBuilder)
1723604d80c67185954d4691ac775be59c499eee3b1csatok                        : mComposingStringBuilder;
1724604d80c67185954d4691ac775be59c499eee3b1csatok                if (!TextUtils.isEmpty(textWithUnderline)) {
1725604d80c67185954d4691ac775be59c499eee3b1csatok                    ic.setComposingText(textWithUnderline, 1);
1726604d80c67185954d4691ac775be59c499eee3b1csatok                }
1727604d80c67185954d4691ac775be59c499eee3b1csatok                mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator);
1728ec780e2868962bf17f0dfd35d36895f543bde40asatok            }
1729ec780e2868962bf17f0dfd35d36895f543bde40asatok        }
1730466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1731466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1732409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void updateSuggestions() {
1733923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Check if we have a suggestion engine attached.
17349fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if ((mSuggest == null || !isSuggestionsRequested())
1735b86905943c0f1cadb2b3df9f2a58e7af84f6b27fsatok                && !mVoiceProxy.isVoiceInputHighlighted()) {
1736923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1737923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1738466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1739cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard        mHandler.cancelUpdateSuggestions();
1740cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard        mHandler.cancelUpdateBigramPredictions();
1741cd95a365586b2b5f9a3639b72a2befdac7ada8a4Jean Chalard
1742f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
1743ca26f20fa4903de46e374babbfba8c8a1a5cac93satok            setPunctuationSuggestions();
1744923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1746979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
17479318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        final WordComposer wordComposer = mWordComposer;
17489f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: May need a better way of retrieving previous word
174940f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        final InputConnection ic = getCurrentInputConnection();
175040f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        final CharSequence prevWord;
175140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        if (null == ic) {
175240f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            prevWord = null;
175340f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        } else {
175440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            prevWord = EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
175540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        }
175640f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        // getSuggestedWordBuilder handles gracefully a null value of prevWord
175740f7efc172928bdd6048e91421a766abe5b22996Jean Chalard        final SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(
1758904baab25a4c6ec5d9c4bf7e562154e3f544d296satok                wordComposer, prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo());
1759923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17608558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        boolean autoCorrectionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
17619318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        final CharSequence typedWord = wordComposer.getTypedWord();
1762bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        // Here, we want to promote a whitelisted word if exists.
17635f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard        // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
17645f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard        // but still autocorrected from - in the case the whitelist only capitalizes the word.
17655f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard        // The whitelist should be case-insensitive, so it's not possible to be consistent with
17665f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard        // a boolean flag. Right now this is handled with a slight hack in
17675f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard        // WhitelistDictionary#shouldForciblyAutoCorrectFrom.
17685f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard        final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected(
1769bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
1770979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (mCorrectionMode == Suggest.CORRECTION_FULL
1771979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
17725f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard            autoCorrectionAvailable |= (!allowsToBeAutoCorrected);
1773923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
17744a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        // Don't auto-correct words with multiple capital letter
17758558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        autoCorrectionAvailable &= !wordComposer.isMostlyCaps();
1776979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1777a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // Basically, we update the suggestion strip only when suggestion count > 1.  However,
1778a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa        // there is an exception: We update the suggestion strip whenever typed word's length
1779f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // is 1 or typed word is found in dictionary, regardless of suggestion count.  Actually,
1780f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // in most cases, suggestion count is 1 when typed word's length is 1, but we do always
1781f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // need to clear the previous state when the user starts typing a word (i.e. typed word's
1782f3df63a93a8f623e2aca5895ee749bd297b58d12Tadashi G. Takaoka        // length == 1).
1783fe1a6d961cf039357f061482461e4d2e951ad346satok        if (typedWord != null) {
17845f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard            if (builder.size() > 1 || typedWord.length() == 1 || (!allowsToBeAutoCorrected)
1785913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    || mSuggestionsView.isShowingAddToDictionaryHint()) {
17865f41b705fc95b21c8edd6226bb50c0fa78a39261Jean Chalard                builder.setTypedWordValid(!allowsToBeAutoCorrected).setHasMinimalSuggestion(
17878558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa                        autoCorrectionAvailable);
1788fe1a6d961cf039357f061482461e4d2e951ad346satok            } else {
1789074cda4d266b5d034d4348961c9183e32b16af5asatok                SuggestedWords previousSuggestions = mSuggestionsView.getSuggestions();
1790074cda4d266b5d034d4348961c9183e32b16af5asatok                if (previousSuggestions == mSettingsValues.mSuggestPuncList) {
1791074cda4d266b5d034d4348961c9183e32b16af5asatok                    if (builder.size() == 0) {
1792074cda4d266b5d034d4348961c9183e32b16af5asatok                        return;
1793074cda4d266b5d034d4348961c9183e32b16af5asatok                    }
1794074cda4d266b5d034d4348961c9183e32b16af5asatok                    previousSuggestions = SuggestedWords.EMPTY;
1795074cda4d266b5d034d4348961c9183e32b16af5asatok                }
1796fe1a6d961cf039357f061482461e4d2e951ad346satok                builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions);
1797fe1a6d961cf039357f061482461e4d2e951ad346satok            }
17989fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        }
17997e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        showSuggestions(builder.build(), typedWord);
1800979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
18014a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
18029fbfd5877305ed19a20663630b498b6b3fdae942satok    public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
18032aa1dd45c44295e2f7e8ece1b520032d86b9f908satok        final boolean shouldBlockAutoCorrectionBySafetyNet =
18042aa1dd45c44295e2f7e8ece1b520032d86b9f908satok                Utils.shouldBlockAutoCorrectionBySafetyNet(suggestedWords, mSuggest);
18052aa1dd45c44295e2f7e8ece1b520032d86b9f908satok        if (shouldBlockAutoCorrectionBySafetyNet) {
18062aa1dd45c44295e2f7e8ece1b520032d86b9f908satok            suggestedWords.setShouldBlockAutoCorrection();
18072aa1dd45c44295e2f7e8ece1b520032d86b9f908satok        }
18087e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        setSuggestions(suggestedWords);
18097e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka        if (suggestedWords.size() > 0) {
18102aa1dd45c44295e2f7e8ece1b520032d86b9f908satok            if (shouldBlockAutoCorrectionBySafetyNet) {
181182411d47ba7e8133ed2390c6920945e139a738cesatok                mBestWord = typedWord;
181282411d47ba7e8133ed2390c6920945e139a738cesatok            } else if (suggestedWords.hasAutoCorrectionWord()) {
18137e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                mBestWord = suggestedWords.getWord(1);
1814923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
1815923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mBestWord = typedWord;
1816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1817923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
1818923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBestWord = null;
1819923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1820913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        setSuggestionStripShown(isSuggestionsStripVisible());
1821923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1823b5d17e52fcda39d540822e615bfb7ed5074e0034satok    private boolean pickDefaultSuggestion(int separatorCode) {
1824913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        // Complete any pending suggestions query first
1825d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        if (mHandler.hasPendingUpdateSuggestions()) {
1826d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            mHandler.cancelUpdateSuggestions();
1827923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            updateSuggestions();
1828923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
18296780b898ec2647a21319601a03ae1c393c0e1b29Amith Yamasani        if (mBestWord != null && mBestWord.length() > 0) {
18309318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode);
18314733609947c0ec74e460bd714fffca0518ade93aJean Chalard            mExpectingUpdateSelection = true;
18321fef530ec7626fa16777f52b48191e61db8f46d4satok            commitBestWord(mBestWord);
1833f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            // Add the word to the user unigram dictionary if it's not a known word
1834f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            addToUserUnigramAndBigramDictionaries(mBestWord,
1835f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                    UserUnigramDictionary.FREQUENCY_FOR_TYPED);
1836979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return true;
1837923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1838979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return false;
1839923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1840923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1841c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
1842923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void pickSuggestionManually(int index, CharSequence suggestion) {
1843604d80c67185954d4691ac775be59c499eee3b1csatok        mComposingStateManager.onFinishComposingText();
1844913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        SuggestedWords suggestions = mSuggestionsView.getSuggestions();
184517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
184617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
18474f1f2201bdd0e63a19e686caa3d17b16eb134f5eMaryam Garrett
18489351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
18499a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
18509a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.beginBatchEdit();
18519a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
18521b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null
18531b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
1854923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (ic != null) {
18559351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
18569351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                ic.commitCompletion(completionInfo);
1857923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mCommittedLength = suggestion.length();
1859913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (mSuggestionsView != null) {
1860913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                mSuggestionsView.clear();
1861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1862b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mKeyboardSwitcher.updateShiftState();
18639a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
18649a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
18659a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
1866923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
1867923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
18686a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
18696a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // If this is a punctuation, apply it through the normal key press
187017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0))
187117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) {
1872979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // Word separators are suggested before the user inputs something.
1873979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // So, LatinImeLogger logs "" as a user's input.
1874979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            LatinImeLogger.logOnManualSuggestion(
18757e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka                    "", suggestion.toString(), index, suggestions.mWords);
1876863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // Find out whether the previous character is a space. If it is, as a special case
1877120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            // for punctuation entered through the suggestion strip, it should be swapped
1878120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            // if it was a magic or a weak space. This is meant to help in case the user
1879863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // pressed space on purpose of displaying the suggestion strip punctuation.
188083ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa            final int rawPrimaryCode = suggestion.charAt(0);
188183ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa            // Maybe apply the "bidi mirrored" conversions for parentheses
188283ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa            final LatinKeyboard keyboard = mKeyboardSwitcher.getLatinKeyboard();
188349426a1ea941c0331a6e573e36cff3c3a8e8849cTadashi G. Takaoka            final boolean isRtl = keyboard != null && keyboard.mIsRtlKeyboard;
188449426a1ea941c0331a6e573e36cff3c3a8e8849cTadashi G. Takaoka            final int primaryCode = Key.getRtlParenthesisCode(rawPrimaryCode, isRtl);
188583ffff2a49beeb41874b7cb40819a75001f708e2Ken Wakasa
1886120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            insertPunctuationFromSuggestionStrip(ic, primaryCode);
1887120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            // TODO: the following endBatchEdit seems useless, check
18889a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            if (ic != null) {
18899a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa                ic.endBatchEdit();
18909a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            }
18916a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            return;
18926a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        }
1893f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        if (!mHasUncommittedTypedChars) {
189489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // If we are not composing a word, then it was a suggestion inferred from
189589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // context - no user input. We should reset the word composer.
18969318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa            mWordComposer.reset();
189789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
18984733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mExpectingUpdateSelection = true;
18991fef530ec7626fa16777f52b48191e61db8f46d4satok        commitBestWord(suggestion);
19009468335a06d2b0e3ef15f4f57f8c1b0857b34ebeAmith Yamasani        // Add the word to the auto dictionary if it's not a known word
19010c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        if (index == 0) {
1902f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            addToUserUnigramAndBigramDictionaries(suggestion,
1903f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard                    UserUnigramDictionary.FREQUENCY_FOR_PICKED);
1904979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } else {
1905bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            addToOnlyBigramDictionary(suggestion, 1);
19060c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        }
19079318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        LatinImeLogger.logOnManualSuggestion(mComposingStringBuilder.toString(),
19089318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa                suggestion.toString(), index, suggestions.mWords);
19099318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        TextEntryState.acceptedSuggestion(mComposingStringBuilder.toString(), suggestion);
1910923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Follow it with a space
1911d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard        if (mInsertSpaceOnPickSuggestionManually) {
19120730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard            sendMagicSpace();
1913923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1914979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1915c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa        // We should show the "Touch again to save" hint if the user pressed the first entry
1916c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa        // AND either:
19177f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is no dictionary (we know that because we tried to load it => null != mSuggest
1918c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa        //   AND mSuggest.hasMainDictionary() is false)
19197f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // - There is a dictionary and the word is not in it
19207f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // Please note that if mSuggest is null, it means that everything is off: suggestion
19217f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // and correction, so we shouldn't try to show the hint
19227f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // We used to look at mCorrectionMode here, but showing the hint should have nothing
19237f2ba16aa2adba95e0575a2c6d58f6240154f313Jean Chalard        // to do with the autocorrection setting.
1924bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok        final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
1925bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                // If there is no dictionary the hint should be shown.
1926c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa                && (!mSuggest.hasMainDictionary()
1927bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        // If "suggestion" is not in the dictionary, the hint should be shown.
1928bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                        || !AutoCorrection.isValidWord(
1929bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                                mSuggest.getUnigramDictionaries(), suggestion, true));
1930b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
1931d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard        // Fool the state watcher so that a subsequent backspace will not do a revert, unless
1932d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard        // we just did a correction, in which case we need to stay in
1933d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard        // TextEntryState.State.PICKED_SUGGESTION state.
1934d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard        TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true,
1935d0c5f9395a1b94e8425982e353d090f972dc44f0Jean Chalard                WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1936777118a40a363ccab69a00016d3156066513cb78Jean Chalard        if (!showingAddToDictionaryHint) {
1937364da8c618303a7764595d2c15ee034a7671365dKen Wakasa            // If we're not showing the "Touch again to save", then show corrections again.
1938979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            // In case the cursor position doesn't change, make sure we show the suggestions again.
193941ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            updateBigramPredictions();
194041ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // Updating the predictions right away may be slow and feel unresponsive on slower
194141ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // terminals. On the other hand if we just postUpdateBigramPredictions() it will
194241ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard            // take a noticeable delay to update them which may feel uneasy.
1943979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
1944b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        if (showingAddToDictionaryHint) {
1945ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka            if (mIsUserDictionaryAvaliable) {
1946644d33d60ea5a87501274488013d65f55238895eKen Wakasa                mSuggestionsView.showAddToDictionaryHint(
1947644d33d60ea5a87501274488013d65f55238895eKen Wakasa                        suggestion, mSettingsValues.mHintToSaveText);
1948ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka            } else {
1949ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka                mHandler.postUpdateSuggestions();
1950ada26bb383f5b9de4717a980a3aa8f53d267df93Tadashi G. Takaoka            }
195166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        }
19529a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        if (ic != null) {
19539a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa            ic.endBatchEdit();
19549a503e07d594ddf3cd0c31609c5311440b975906Ken Wakasa        }
1955923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1956a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1957979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
19588558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa     * Commits the chosen word to the text field and saves it for later retrieval.
1959979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
19601fef530ec7626fa16777f52b48191e61db8f46d4satok    private void commitBestWord(CharSequence bestWord) {
19619351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final KeyboardSwitcher switcher = mKeyboardSwitcher;
1962b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!switcher.isKeyboardAvailable())
19631679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            return;
19649351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
1965923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic != null) {
19661fef530ec7626fa16777f52b48191e61db8f46d4satok            mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators);
19671531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard            if (mSettingsValues.mEnableSuggestionSpanInsertion) {
19681531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard                final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
19691531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard                ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan(
19701531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard                        this, bestWord, suggestedWords), 1);
19711531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard            } else {
19721531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard                ic.commitText(bestWord, 1);
19731531528bfe01d0ce88888d23952a4c7092a15f17Jean Chalard            }
1974923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1975f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        mHasUncommittedTypedChars = false;
19761fef530ec7626fa16777f52b48191e61db8f46d4satok        mCommittedLength = bestWord.length();
1977923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1978923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
197989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    private static final WordComposer sEmptyWordComposer = new WordComposer();
198041ec3ec2f3a95f0af2697da92cee4920e6156763Jean Chalard    public void updateBigramPredictions() {
198189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (mSuggest == null || !isSuggestionsRequested())
198289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            return;
198389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
198417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mBigramPredictionEnabled) {
1985cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            setPunctuationSuggestions();
1986cb3320179d39a7983874697a0aa428b127675c9dJean Chalard            return;
1987cb3320179d39a7983874697a0aa428b127675c9dJean Chalard        }
1988cb3320179d39a7983874697a0aa428b127675c9dJean Chalard
198989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        final CharSequence prevWord = EditingUtils.getThisWord(getCurrentInputConnection(),
199017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                mSettingsValues.mWordSeparators);
1991904baab25a4c6ec5d9c4bf7e562154e3f544d296satok        SuggestedWords.Builder builder = mSuggest.getSuggestedWordBuilder(sEmptyWordComposer,
1992904baab25a4c6ec5d9c4bf7e562154e3f544d296satok                prevWord, mKeyboardSwitcher.getLatinKeyboard().getProximityInfo());
199389bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
199489bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        if (builder.size() > 0) {
199589bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // Explicitly supply an empty typed word (the no-second-arg version of
199689bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            // showSuggestions will retrieve the word near the cursor, we don't want that here)
199789bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            showSuggestions(builder.build(), "");
199889bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        } else {
199989bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard            if (!isShowingPunctuationList()) setPunctuationSuggestions();
200089bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard        }
200189bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard    }
200289bd776cf68150202d774d62cc1c88664aea5e9fJean Chalard
20037a8dac55278cedd838be325f56b4c52d973c61f5satok    public void setPunctuationSuggestions() {
200417c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        setSuggestions(mSettingsValues.mSuggestPuncList);
2005913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        setSuggestionStripShown(isSuggestionsStripVisible());
20066a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
20076a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
2008f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard    private void addToUserUnigramAndBigramDictionaries(CharSequence suggestion,
2009f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard            int frequencyDelta) {
2010979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, false);
2011979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2012979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2013bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok    private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
2014979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        checkAddToDictionary(suggestion, frequencyDelta, true);
2015979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2016979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2017979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    /**
2018f4223452119f9ff8b52f026f7ef92d961736dc51Jean Chalard     * Adds to the UserBigramDictionary and/or UserUnigramDictionary
2019bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok     * @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
2020979f8690967ff5409fe18f5085858ccdb8e0ccf1satok     */
2021979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
2022bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            boolean selectedANotTypedWord) {
2023979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (suggestion == null || suggestion.length() < 1) return;
2024bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
20250c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
20260c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // adding words in situations where the user or application really didn't
20270c05902e331b03426754a1cfffe28d185dd8338cAmith Yamasani        // want corrections enabled or learned.
2028979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (!(mCorrectionMode == Suggest.CORRECTION_FULL
2029979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                || mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
2030979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            return;
2031979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
2032bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok
20335955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard        if (null != mSuggest && null != mUserUnigramDictionary) {
20345955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard            final boolean selectedATypedWordAndItsInUserUnigramDic =
20355955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard                    !selectedANotTypedWord && mUserUnigramDictionary.isValidWord(suggestion);
20365955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard            final boolean isValidWord = AutoCorrection.isValidWord(
20375955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard                    mSuggest.getUnigramDictionaries(), suggestion, true);
20385955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard            final boolean needsToAddToUserUnigramDictionary =
20395955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard                    selectedATypedWordAndItsInUserUnigramDic || !isValidWord;
20405955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard            if (needsToAddToUserUnigramDictionary) {
20415955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard                mUserUnigramDictionary.addWord(suggestion.toString(), frequencyDelta);
20425955cfdaeae9ce2120769a4be965bdbac413bf79Jean Chalard            }
2043e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        }
2044979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2045e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mUserBigramDictionary != null) {
2046863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // We don't want to register as bigrams words separated by a separator.
2047863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // For example "I will, and you too" : we don't want the pair ("will" "and") to be
2048863f95b6052e5d9d4fb1ac5dc283c464db9f29c3Jean Chalard            // a bigram.
204940f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            final InputConnection ic = getCurrentInputConnection();
205040f7efc172928bdd6048e91421a766abe5b22996Jean Chalard            if (null != ic) {
205140f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                final CharSequence prevWord =
205240f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                        EditingUtils.getPreviousWord(ic, mSettingsValues.mWordSeparators);
205340f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                if (!TextUtils.isEmpty(prevWord)) {
205440f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                    mUserBigramDictionary.addBigrams(prevWord.toString(), suggestion.toString());
205540f7efc172928bdd6048e91421a766abe5b22996Jean Chalard                }
2056979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
205732e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani        }
205832e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani    }
205932e1c1c338155f8a83646d725a8512b95edad4f8Amith Yamasani
20607a8dac55278cedd838be325f56b4c52d973c61f5satok    public boolean isCursorTouchingWord() {
20619351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final InputConnection ic = getCurrentInputConnection();
2062923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (ic == null) return false;
2063923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
2064923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence toRight = ic.getTextAfterCursor(1, 0);
2065923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (!TextUtils.isEmpty(toLeft)
206617c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toLeft.charAt(0))
206717c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) {
2068923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
2069923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2070a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker        if (!TextUtils.isEmpty(toRight)
207117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isWordSeparator(toRight.charAt(0))
207217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) {
2073923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
2074923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2075923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return false;
2076923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2077a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2078120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // "ic" must not be null
20799351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) {
2080dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
2081dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani        return TextUtils.equals(text, beforeText);
2082dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani    }
2083dad0e792aa064765901224af56d2a53a25bc7b7dAmith Yamasani
2084120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // "ic" must not be null
20859351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private void revertLastWord(final InputConnection ic) {
20868558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) {
2087923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
20888558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            return;
20898558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        }
20908558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa
20919351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        final CharSequence separator = ic.getTextBeforeCursor(1, 0);
209220c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa        ic.deleteSurroundingText(1, 0);
209320c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa        final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
209420c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa        ic.deleteSurroundingText(mCommittedLength, 0);
20959351550dc6af7859e5280e16144c9386a37b976dKen Wakasa
20969351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        // Re-insert "separator" only when the deleted character was word separator and the
20979351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        // composing text wasn't equal to the auto-corrected text which can be found before
20989351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        // the cursor.
20999351550dc6af7859e5280e16144c9386a37b976dKen Wakasa        if (!TextUtils.isEmpty(separator)
21009351550dc6af7859e5280e16144c9386a37b976dKen Wakasa                && mSettingsValues.isWordSeparator(separator.charAt(0))
210120c4aec82719b5e9b5ddfa990970f19d399aaa2cKen Wakasa                && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) {
21028558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            ic.commitText(mComposingStringBuilder, 1);
21038558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.acceptedTyped(mComposingStringBuilder);
21049351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            ic.commitText(separator, 1);
21059351550dc6af7859e5280e16144c9386a37b976dKen Wakasa            TextEntryState.typedCharacter(separator.charAt(0), true,
21068558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa                    WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
21078558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            // Clear composing text
21088558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            mComposingStringBuilder.setLength(0);
21098558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        } else {
21108558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            mHasUncommittedTypedChars = true;
21118558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            ic.setComposingText(mComposingStringBuilder, 1);
21128558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa            TextEntryState.backspace();
2113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
21148558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        mHandler.cancelUpdateBigramPredictions();
21158558cfb42a412010f2e5320ee50fe44afefdc1cfKen Wakasa        mHandler.postUpdateSuggestions();
2116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2118120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    // "ic" must not be null
21199351550dc6af7859e5280e16144c9386a37b976dKen Wakasa    private boolean revertDoubleSpace(final InputConnection ic) {
21204733609947c0ec74e460bd714fffca0518ade93aJean Chalard        mHandler.cancelDoubleSpacesTimer();
21214733609947c0ec74e460bd714fffca0518ade93aJean Chalard        // Here we test whether we indeed have a period and a space before us. This should not
21224733609947c0ec74e460bd714fffca0518ade93aJean Chalard        // be needed, but it's there just in case something went wrong.
21234733609947c0ec74e460bd714fffca0518ade93aJean Chalard        final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
21244733609947c0ec74e460bd714fffca0518ade93aJean Chalard        if (!". ".equals(textBeforeCursor))
21254733609947c0ec74e460bd714fffca0518ade93aJean Chalard            return false;
21264733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.beginBatchEdit();
21274733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.deleteSurroundingText(2, 0);
21284733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.commitText("  ", 1);
21294733609947c0ec74e460bd714fffca0518ade93aJean Chalard        ic.endBatchEdit();
21304733609947c0ec74e460bd714fffca0518ade93aJean Chalard        return true;
21314733609947c0ec74e460bd714fffca0518ade93aJean Chalard    }
21324733609947c0ec74e460bd714fffca0518ade93aJean Chalard
2133120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    private boolean revertSwapPunctuation(final InputConnection ic) {
2134120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // Here we test whether we indeed have a space and something else before us. This should not
2135120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // be needed, but it's there just in case something went wrong.
2136120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0);
2137120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to
2138120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        // enter surrogate pairs this code will have been removed.
2139120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        if (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))
2140120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard            return false;
2141120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        ic.beginBatchEdit();
2142120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        ic.deleteSurroundingText(2, 0);
2143120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        ic.commitText(" " + textBeforeCursor.subSequence(0, 1), 1);
2144120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        ic.endBatchEdit();
2145120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        return true;
2146120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard    }
2147120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard
2148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean isWordSeparator(int code) {
214917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.isWordSeparator(code);
2150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21520730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard    private void sendMagicSpace() {
2153571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        sendKeyChar((char)Keyboard.CODE_SPACE);
2154120586c226c416d2211b6ebb3f4b914a30f9a74fJean Chalard        mSpaceState = SPACE_STATE_MAGIC;
2155b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mKeyboardSwitcher.updateShiftState();
2156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean preferCapitalization() {
21599318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        return mWordComposer.isFirstCharCapitalized();
2160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
216288fc9d44186120f9edc5cf7ec0e2af85260fed04satok    // Notify that language or mode have been changed and toggleLanguage will update KeyboardID
2163c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    // according to new language or mode.
2164c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    public void onRefreshKeyboard() {
216555303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka        if (!CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) {
216655303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka            // Before Honeycomb, Voice IME is in LatinIME and it changes the current input view,
216755303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka            // so that we need to re-create the keyboard input view here.
216855303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka            setInputView(mKeyboardSwitcher.onCreateInputView());
216955303bc63440c6a9547e94b4f3486a00696da9b0Tadashi G. Takaoka        }
21704ab730dbd34fad323063f2ffd31ce33de746668dsatok        // Reload keyboard because the current language has been changed.
2171255486a5d067469e074f3649b3d2747e7a08aaa2Tadashi G. Takaoka        mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettingsValues);
21720ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        initSuggest();
217317c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        loadSettings();
217436fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
217536fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
2176d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka    private void hapticAndAudioFeedback(int primaryCode) {
2177d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka        vibrate();
2178d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka        playKeyClick(primaryCode);
2179d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka    }
2180d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka
21815a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
2182e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPress(int primaryCode, boolean withSliding) {
2183055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
2184055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        if (switcher.isVibrateAndSoundFeedbackRequired()) {
2185d999ea44805ae0a3ccac4c4f49aaf500f6c479acTadashi G. Takaoka            hapticAndAudioFeedback(primaryCode);
2186cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka        }
21871679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
2188571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
2189e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onPressShift(withSliding);
2190e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
21916c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onPressSymbol();
219240a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        } else {
21936c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onOtherKeyPressed();
2194681b102a492b7d5301c1ca87985b4c391eb5eb14Tadashi G. Takaoka        }
2195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
21975a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
2198e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onRelease(int primaryCode, boolean withSliding) {
21991679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        KeyboardSwitcher switcher = mKeyboardSwitcher;
22003f7d75060afb2bb7e74879bcbbdcb9700ec5c2d6Amith Yamasani        // Reset any drag flags in the keyboard
22011679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
2202571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
2203e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            switcher.onReleaseShift(withSliding);
2204e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
22056c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka            switcher.onReleaseSymbol();
220640a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka        }
2207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2208a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2209a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2210123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka    // receive ringer mode change and network state change.
2211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
2212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
2213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2214123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
2215123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
2216123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                updateRingerMode();
2217123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
2218123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka                mSubtypeSwitcher.onNetworkStateChanged(intent);
2219123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
2220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
2222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
222379c0acf51984256d640b38ea3c394f308cc3b314satok    // update keypress sound volume
2224bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa    private void updateSoundEffectVolume() {
222579c0acf51984256d640b38ea3c394f308cc3b314satok        mFxVolume = Utils.getCurrentKeypressSoundVolume(mPrefs, mResources);
2226bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa    }
2227bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa
2228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // update flags for silent mode
2229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateRingerMode() {
2230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2232bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa            if (mAudioManager == null) return;
2233923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2234bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa        mSilentModeOn = (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL);
2235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
223728f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa    private void updateKeypressVibrationDuration() {
2238433965784dca1a2cd801e1aab8c8258f64d8c7e0satok        mKeypressVibrationDuration = Utils.getCurrentVibrationDuration(mPrefs, mResources);
223928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa    }
224028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa
2241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void playKeyClick(int primaryCode) {
2242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // if mAudioManager is null, we don't have the ringer state yet
2243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // mAudioManager will be set by updateRingerMode
2244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mAudioManager == null) {
2245c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            if (mKeyboardSwitcher.getKeyboardView() != null) {
2246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                updateRingerMode();
2247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
224917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (isSoundOn()) {
2250f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa            final int sound;
2251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (primaryCode) {
2252f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa            case Keyboard.CODE_DELETE:
2253f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                sound = AudioManager.FX_KEYPRESS_DELETE;
2254f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                break;
2255f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa            case Keyboard.CODE_ENTER:
2256f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                sound = AudioManager.FX_KEYPRESS_RETURN;
2257f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                break;
2258f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa            case Keyboard.CODE_SPACE:
2259f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                sound = AudioManager.FX_KEYPRESS_SPACEBAR;
2260f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                break;
2261f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa            default:
2262f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                sound = AudioManager.FX_KEYPRESS_STANDARD;
2263f58293f6ebf821acd9a3cc594124e905c4592810Ken Wakasa                break;
2264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2265bf7dd47329c23c846912b268d15e8083ffdaabdeKen Wakasa            mAudioManager.playSoundEffect(sound, mFxVolume);
2266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2267923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2269409220583333bdf06290dd9fd42f91b5c0d1b11asatok    public void vibrate() {
227017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        if (!mSettingsValues.mVibrateOn) {
2271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
2272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
227328f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa        if (mKeypressVibrationDuration < 0) {
227428f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa            // Go ahead with the system default
227528f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa            LatinKeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
227628f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa            if (inputView != null) {
227728f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa                inputView.performHapticFeedback(
227828f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa                        HapticFeedbackConstants.KEYBOARD_TAP,
227928f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa                        HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
228028f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa            }
228128f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa        } else if (mVibrator != null) {
228228f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa            mVibrator.vibrate(mKeypressVibrationDuration);
2283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
228671c353aa875f5237b1dce4e18bd4fe86ce28b58eTadashi G. Takaoka    public WordComposer getCurrentWord() {
22879318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        return mWordComposer;
22886516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani    }
22896516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani
229017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    boolean isSoundOn() {
229117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        return mSettingsValues.mSoundOn && !mSilentModeOn;
2292979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
2293979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
2294e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    private void updateCorrectionMode() {
22959f67e12a0e3f77985fb8bafe0db4c00e32317b9asatok        // TODO: cleanup messy flags
2296f50aa193377492e9c4afb3cc6e7f3448ab5a97a4Jean Chalard        final boolean shouldAutoCorrect = mSettingsValues.mAutoCorrectEnabled
2297c769ef4dd17ff9561e99528624f74b9072a09fbbKen Wakasa                && !mInputTypeNoAutoCorrect;
229817c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (shouldAutoCorrect && mSettingsValues.mAutoCorrectEnabled)
2299e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani                ? Suggest.CORRECTION_FULL
230017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                : (shouldAutoCorrect ? Suggest.CORRECTION_BASIC : Suggest.CORRECTION_NONE);
230117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        mCorrectionMode = (mSettingsValues.mBigramSuggestionEnabled && shouldAutoCorrect
230217c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard                && mSettingsValues.mAutoCorrectEnabled)
2303979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                ? Suggest.CORRECTION_FULL_BIGRAM : mCorrectionMode;
2304e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        if (mSuggest != null) {
2305e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani            mSuggest.setCorrectionMode(mCorrectionMode);
2306e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani        }
2307e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani    }
2308e8f1edefeb2375a253d742c7f95e8d91677c7073Amith Yamasani
230917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    private void updateSuggestionVisibility(final SharedPreferences prefs, final Resources res) {
23107599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        final String suggestionVisiblityStr = prefs.getString(
23119502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                Settings.PREF_SHOW_SUGGESTIONS_SETTING,
2312458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa                res.getString(R.string.prefs_suggestion_visibility_default_value));
23137599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
2314458249e703bded3a1cbd25a2ab2249f9366a8188Ken Wakasa            if (suggestionVisiblityStr.equals(res.getString(visibility))) {
23157599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                mSuggestionVisibility = visibility;
23167599cfea4a2d56f4779452ec8e8742f7b9629cc0satok                break;
23177599cfea4a2d56f4779452ec8e8742f7b9629cc0satok            }
23187599cfea4a2d56f4779452ec8e8742f7b9629cc0satok        }
23197599cfea4a2d56f4779452ec8e8742f7b9629cc0satok    }
23207599cfea4a2d56f4779452ec8e8742f7b9629cc0satok
2321466741d8a78965b8509bf527344f289e50873092Mike LeBeau    protected void launchSettings() {
2322cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        launchSettingsClass(Settings.class);
2323466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
2324466741d8a78965b8509bf527344f289e50873092Mike LeBeau
2325bf96661d33d0126adb60a48880ceba1ff055d4a4satok    public void launchDebugSettings() {
2326cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        launchSettingsClass(DebugSettings.class);
2327bf96661d33d0126adb60a48880ceba1ff055d4a4satok    }
2328bf96661d33d0126adb60a48880ceba1ff055d4a4satok
2329cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    protected void launchSettingsClass(Class<? extends PreferenceActivity> settingsClass) {
2330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        handleClose();
2331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Intent intent = new Intent();
2332466741d8a78965b8509bf527344f289e50873092Mike LeBeau        intent.setClass(LatinIME.this, settingsClass);
2333923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2334923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
2335923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2336923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23372fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
233885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
233985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
234085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                // TODO: Should use new string "Select active input modes".
234185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.language_selection_title),
234285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
234385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
234485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23452fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
23462fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
23472fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
23482fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
234985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
23502cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                    Intent intent = CompatUtils.getInputLanguageSelectionIntent(
23512cff4d7e4abdb192151f9b4027fc93fe28a8bdaasatok                            mInputMethodId, Intent.FLAG_ACTIVITY_NEW_TASK
23522fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
23532fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                            | Intent.FLAG_ACTIVITY_CLEAR_TOP);
23542fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
23552fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2356aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
2357aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    launchSettings();
2358aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
23592fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
23602fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
236185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
2362bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        final AlertDialog.Builder builder = new AlertDialog.Builder(this)
2363bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setItems(items, listener)
2364bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setTitle(title);
2365bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        showOptionDialogInternal(builder.create());
23662fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
2367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23682fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showOptionsMenu() {
236985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
237085996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
237185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.selectInputMethod),
237285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                getString(R.string.english_ime_settings),
237385996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
237485996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
23755a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            @Override
2376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onClick(DialogInterface di, int position) {
2377923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                di.dismiss();
2378923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                switch (position) {
237985996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
2380ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    mImm.showInputMethodPicker();
23812fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
238285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 1:
2383ea55bf5df7d26d12b36c47141bfbac5730c3929aTadashi G. Takaoka                    launchSettings();
23842fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
2385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
2386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
238785996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
2388bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        final AlertDialog.Builder builder = new AlertDialog.Builder(this)
2389bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setItems(items, listener)
2390bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka                .setTitle(title);
2391bf9d8348d89be257ccc3db75333bfd4cdf0a9b7eTadashi G. Takaoka        showOptionDialogInternal(builder.create());
2392923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23947e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
23957e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
2396923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
2397a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
2399923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
2400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
24019318d33b6e501d4dd9ea860de04160ccb23a7501Ken Wakasa        p.println("  mComposingStringBuilder=" + mComposingStringBuilder.toString());
24029fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        p.println("  mIsSuggestionsRequested=" + mIsSettingsSuggestionStripOn);
2403923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  mCorrectionMode=" + mCorrectionMode);
2404f108bf8fe924722ac6fc451f0235eb85a60f459dJean Chalard        p.println("  mHasUncommittedTypedChars=" + mHasUncommittedTypedChars);
240517c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mAutoCorrectEnabled=" + mSettingsValues.mAutoCorrectEnabled);
240626a531c6fe2a6e058803b7102e2bc9e7ea12d8f3Jean Chalard        p.println("  mInsertSpaceOnPickSuggestionManually=" + mInsertSpaceOnPickSuggestionManually);
24071b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        p.println("  mApplicationSpecifiedCompletionOn=" + mApplicationSpecifiedCompletionOn);
2408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("  TextEntryState.state=" + TextEntryState.getState());
240917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mSoundOn=" + mSettingsValues.mSoundOn);
241017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard        p.println("  mVibrateOn=" + mSettingsValues.mVibrateOn);
2411240297d0ee186b14e795016e9b1bd168c8d8acf8Jean Chalard        p.println("  mKeyPreviewPopupOn=" + mSettingsValues.mKeyPreviewPopupOn);
2412923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
24136e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani
2414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    // Characters per second measurement
2415a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long mLastCpsTime;
2417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int CPS_BUFFER_SIZE = 16;
2418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private long[] mCpsIntervals = new long[CPS_BUFFER_SIZE];
2419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCpsIndex;
2420a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
2421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void measureCps() {
2422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long now = System.currentTimeMillis();
2423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mLastCpsTime == 0) mLastCpsTime = now - 100; // Initial
2424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIntervals[mCpsIndex] = now - mLastCpsTime;
2425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mLastCpsTime = now;
2426923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCpsIndex = (mCpsIndex + 1) % CPS_BUFFER_SIZE;
2427923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        long total = 0;
2428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < CPS_BUFFER_SIZE; i++) total += mCpsIntervals[i];
2429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        System.out.println("CPS = " + ((CPS_BUFFER_SIZE * 1000f) / total));
2430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2431923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
2432