1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
7a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      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
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under 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
199342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport static com.android.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
209342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
219342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
221cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka
23604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheikimport android.Manifest.permission;
24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.app.AlertDialog;
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.BroadcastReceiver;
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.DialogInterface;
286abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaokaimport android.content.DialogInterface.OnClickListener;
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Intent;
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.IntentFilter;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.res.Configuration;
3236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
336c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonakaimport android.graphics.Color;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.inputmethodservice.InputMethodService;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.media.AudioManager;
3660b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawaimport android.os.Build;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Debug;
3881d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaokaimport android.os.IBinder;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
402dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaokaimport android.preference.PreferenceManager;
41e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.InputType;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Log;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.PrintWriterPrinter;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.Printer;
455eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalardimport android.util.SparseArray;
4637beaf1529a61228d6240736937789e5622b29edTadashi G. Takaokaimport android.view.Gravity;
474e1a558ee8d7747b71dba5aac86a7c9003d6f57dJean Chalardimport android.view.KeyEvent;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
49c160a3932f74fea72c5347798c001d4ae961864cKen Wakasaimport android.view.ViewGroup.LayoutParams;
5013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.Window;
5113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaokaimport android.view.WindowManager;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.CompletionInfo;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.inputmethod.EditorInfo;
549cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype;
55c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka
565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibilityUtils;
5715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting;
5860b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawaimport com.android.inputmethod.compat.BuildCompatUtils;
59809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawaimport com.android.inputmethod.compat.EditorInfoCompatUtils;
60fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasaimport com.android.inputmethod.compat.InputMethodServiceCompatUtils;
61809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawaimport com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
6215480481be790c913b0117d0841565efd399cd01Tadashi G. Takaokaimport com.android.inputmethod.compat.ViewOutlineProviderCompatUtils;
6315480481be790c913b0117d0841565efd399cd01Tadashi G. Takaokaimport com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
641061bfdb34bbcb63bf0046eec42313d264ac33faJean Chalardimport com.android.inputmethod.dictionarypack.DictionaryPackConstants;
65a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalardimport com.android.inputmethod.event.Event;
665eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalardimport com.android.inputmethod.event.HardwareEventDecoder;
675eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalardimport com.android.inputmethod.event.HardwareKeyboardEventDecoder;
68a1bf550294dfb5e6e7e5eba78a8db491c5bab2d4Jean Chalardimport com.android.inputmethod.event.InputTransaction;
69c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
70c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
716b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId;
72c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
73c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView;
749666a228153bb2269da8983762bdd47e448f2cecYuichiro Hanadaimport com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback;
759310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
769342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants;
775b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.CoordinateUtils;
7836799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardimport com.android.inputmethod.latin.common.InputPointers;
792dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaokaimport com.android.inputmethod.latin.define.DebugFlags;
805a5ee95faead8a2ae749067716481e86faf5f113Tadashi G. Takaokaimport com.android.inputmethod.latin.define.ProductionFlags;
817bd2a75ca180cb5da8ba75500163aa06f332caacJean Chalardimport com.android.inputmethod.latin.inputlogic.InputLogic;
82604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheikimport com.android.inputmethod.latin.permissions.PermissionsManager;
83f1457e7a221082688b6399853e84e77948633c7bKeisuke Kuroyanagiimport com.android.inputmethod.latin.personalization.PersonalizationHelper;
84a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.Settings;
85a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.SettingsActivity;
86a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.SettingsValues;
874702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.SuggestionStripView;
88ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalardimport com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
89c92c883fdf2287b49392692fa2e8d109dc26f785David Fadenimport com.android.inputmethod.latin.touchinputconsumer.GestureConsumer;
904be6198cb73cc24e10834153c4e049644ed187e3Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.ApplicationUtils;
919b46ddc1d51fac37f970e108f7d93eb9ea11e1beTadashi G. Takaokaimport com.android.inputmethod.latin.utils.DialogUtils;
92342e81e7a6cfec8054a8978a9bb84b68e76a01b0Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.ImportantNoticeUtils;
93e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.IntentUtils;
94bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasaimport com.android.inputmethod.latin.utils.JniUtils;
952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
96dc0f7ca167df5b49daa4707d4f737f683b052dabYohei Yukawaimport com.android.inputmethod.latin.utils.StatsUtils;
97aabb3512791979a00c0ab50c0be808f46d18cbe6Jatin Mataniimport com.android.inputmethod.latin.utils.StatsUtilsManager;
98bcd30bf3e74c7c10d5b69a54cdf90c6b682a0747Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
9937beaf1529a61228d6240736937789e5622b29edTadashi G. Takaokaimport com.android.inputmethod.latin.utils.ViewLayoutUtils;
100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
101466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.FileDescriptor;
102466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.io.PrintWriter;
1034ee186920e642ae8ebe0b6c97dfdceb0ad2fdeefJean Chalardimport java.util.ArrayList;
1041fa3e9044f4bb7d1eb62118c94a2223af69c14b0Keisuke Kuroyanagiimport java.util.List;
105466741d8a78965b8509bf527344f289e50873092Mike LeBeauimport java.util.Locale;
1069f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagiimport java.util.concurrent.TimeUnit;
107466741d8a78965b8509bf527344f289e50873092Mike LeBeau
108c4ffa235e5490c3cba211b469c7f125d162f9f86Tadashi G. Takaokaimport javax.annotation.Nonnull;
109c4ffa235e5490c3cba211b469c7f125d162f9f86Tadashi G. Takaoka
110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Input method implementation for Qwerty'ish keyboard.
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
113c9aaba125365cf767356a4bea442153e95bbf6a1Jean Chalardpublic class LatinIME extends InputMethodService implements KeyboardActionListener,
114ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard        SuggestionStripView.Listener, SuggestionStripViewAccessor,
115a1035be6d877cafda95b2761f9697474b79deeb8Keisuke Kuroyanagi        DictionaryFacilitator.DictionaryInitializationListener,
116604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheik        PermissionsManager.PermissionsResultCallback {
1175f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    static final String TAG = LatinIME.class.getSimpleName();
118409220583333bdf06290dd9fd42f91b5c0d1b11asatok    private static final boolean TRACE = false;
119a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1209e347d3d448e48229c46aad394ec9bd60cd5807bsatok    private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
121ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    private static final int PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT = 2;
1227b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu    private static final int PENDING_IMS_CALLBACK_DURATION_MILLIS = 800;
1235f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    static final long DELAY_WAIT_FOR_DICTIONARY_LOAD_MILLIS = TimeUnit.SECONDS.toMillis(2);
1245f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    static final long DELAY_DEALLOCATE_MEMORY_MILLIS = TimeUnit.SECONDS.toMillis(10);
125ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka
126cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    /**
127cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * The name of the scheme used by the Package Manager to warn of a new package installation,
128cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     * replacement or removal.
129cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard     */
130cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    private static final String SCHEME_PACKAGE = "package";
131cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
1325f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    final Settings mSettings;
13315acbdc9050a04f3c5d8724bb3902a57084c96dbJatin Matani    private final DictionaryFacilitator mDictionaryFacilitator =
134b684d2d2e4ae4a43a6f499a263a421760fc5c175Jatin Matani            DictionaryFacilitatorProvider.getDictionaryFacilitator(
135b684d2d2e4ae4a43a6f499a263a421760fc5c175Jatin Matani                    false /* isNeededForSpellChecking */);
1365f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    final InputLogic mInputLogic = new InputLogic(this /* LatinIME */,
137a1035be6d877cafda95b2761f9697474b79deeb8Keisuke Kuroyanagi            this /* SuggestionStripViewAccessor */, mDictionaryFacilitator);
1385eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard    // We expect to have only one decoder in almost all cases, hence the default capacity of 1.
1395eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard    // If it turns out we need several, it will get grown seamlessly.
140a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka    final SparseArray<HardwareEventDecoder> mHardwareEventDecoders = new SparseArray<>(1);
14117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
1428fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka    // TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
1438fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka    private View mInputView;
14415480481be790c913b0117d0841565efd399cd01Tadashi G. Takaoka    private InsetsUpdater mInsetsUpdater;
1454702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    private SuggestionStripView mSuggestionStripView;
1467bd2a75ca180cb5da8ba75500163aa06f332caacJean Chalard
1476fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private RichInputMethodManager mRichImm;
14815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
1491931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    private final SubtypeState mSubtypeState = new SubtypeState();
1501fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic    private EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector;
151aabb3512791979a00c0ab50c0be808f46d18cbe6Jatin Matani    private StatsUtilsManager mStatsUtilsManager;
15288f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka    // Working variable for {@link #startShowingInputView()} and
15388f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka    // {@link #onEvaluateInputViewShown()}.
15488f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka    private boolean mIsExecutingStartShowingInputView;
155a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
156cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    // Object for reacting to adding/removing a dictionary pack.
15723246ed18d9b26d8a7673140c00e060022be935bKeisuke Kuroyanagi    private final BroadcastReceiver mDictionaryPackInstallReceiver =
158efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge            new DictionaryPackInstallBroadcastReceiver(this);
159cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
16023246ed18d9b26d8a7673140c00e060022be935bKeisuke Kuroyanagi    private final BroadcastReceiver mDictionaryDumpBroadcastReceiver =
16136c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi            new DictionaryDumpBroadcastReceiver(this);
16236c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi
16313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka    private AlertDialog mOptionsDialog;
16413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka
165fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa    private final boolean mIsHardwareAcceleratedDrawingEnabled;
166fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa
167c92c883fdf2287b49392692fa2e8d109dc26f785David Faden    private GestureConsumer mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER;
168c92c883fdf2287b49392692fa2e8d109dc26f785David Faden
1694f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    public final UIHandler mHandler = new UIHandler(this);
170d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
1712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public static final class UIHandler extends LeakGuardHandlerWrapper<LatinIME> {
17227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        private static final int MSG_UPDATE_SHIFT_STATE = 0;
17327e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        private static final int MSG_PENDING_IMS_CALLBACK = 1;
17427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTION_STRIP = 2;
175f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3;
1766a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard        private static final int MSG_RESUME_SUGGESTIONS = 4;
177673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        private static final int MSG_REOPEN_DICTIONARIES = 5;
178a777c1c46073d7dc56590e58bdedb497bdfad182Jean Chalard        private static final int MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED = 6;
179f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard        private static final int MSG_RESET_CACHES = 7;
180fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        private static final int MSG_WAIT_FOR_DICTIONARY_LOAD = 8;
1817b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        private static final int MSG_DEALLOCATE_MEMORY = 9;
1829444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard        private static final int MSG_RESUME_SUGGESTIONS_FOR_START_INPUT = 10;
183809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        private static final int MSG_SWITCH_LANGUAGE_AUTOMATICALLY = 11;
1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        // Update this when adding new messages
185809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        private static final int MSG_LAST = MSG_SWITCH_LANGUAGE_AUTOMATICALLY;
186f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka
187908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada        private static final int ARG1_NOT_GESTURE_INPUT = 0;
188f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
189908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada        private static final int ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT = 2;
190084c9961f4ede347fbfb719ce1075a10b93867c3Jean Chalard        private static final int ARG2_UNUSED = 0;
191fca2c4b4398ae2aa505de223d602c5b3dd98faffJean Chalard        private static final int ARG1_TRUE = 1;
1924c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka
193a61b7245b030395451b4c42ec218a946aa95e030Yohei Yukawa        private int mDelayInMillisecondsToUpdateSuggestions;
194a61b7245b030395451b4c42ec218a946aa95e030Yohei Yukawa        private int mDelayInMillisecondsToUpdateShiftState;
19538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
196c4ffa235e5490c3cba211b469c7f125d162f9f86Tadashi G. Takaoka        public UIHandler(@Nonnull final LatinIME ownerInstance) {
1972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            super(ownerInstance);
19810dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka        }
199175acb8205fcc2a91de4059e8a12af49484af784Tadashi G. Takaoka
20010dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka        public void onCreate() {
20198534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            final LatinIME latinIme = getOwnerInstance();
20298534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            if (latinIme == null) {
20398534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                return;
20498534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            }
20598534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            final Resources res = latinIme.getResources();
206bea17c49ec23bf0f646cb548445c7756aa50d233Yohei Yukawa            mDelayInMillisecondsToUpdateSuggestions = res.getInteger(
207bea17c49ec23bf0f646cb548445c7756aa50d233Yohei Yukawa                    R.integer.config_delay_in_milliseconds_to_update_suggestions);
208bea17c49ec23bf0f646cb548445c7756aa50d233Yohei Yukawa            mDelayInMillisecondsToUpdateShiftState = res.getInteger(
209bea17c49ec23bf0f646cb548445c7756aa50d233Yohei Yukawa                    R.integer.config_delay_in_milliseconds_to_update_shift_state);
2104f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
2114f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
213f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        public void handleMessage(final Message msg) {
2142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            final LatinIME latinIme = getOwnerInstance();
21598534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            if (latinIme == null) {
21698534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                return;
21798534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            }
2184f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final KeyboardSwitcher switcher = latinIme.mKeyboardSwitcher;
219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
220dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard            case MSG_UPDATE_SUGGESTION_STRIP:
221151761a2764c09c0e5bc48c68e0c804aeaf22d11Jean Chalard                cancelUpdateSuggestionStrip();
2222a6de7903c1aabad9911638f90cfca12ce64c1e1Jean Chalard                latinIme.mInputLogic.performUpdateSuggestionStripSync(
223b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard                        latinIme.mSettings.getCurrent(), msg.arg1 /* inputStyle */);
224d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
225d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            case MSG_UPDATE_SHIFT_STATE:
2268ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard                switcher.requestUpdatingShiftState(latinIme.getCurrentAutoCapsState(),
2278ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard                        latinIme.getCurrentRecapitalizeState());
228d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka                break;
229f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka            case MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP:
230908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                if (msg.arg1 == ARG1_NOT_GESTURE_INPUT) {
231084c9961f4ede347fbfb719ce1075a10b93867c3Jean Chalard                    final SuggestedWords suggestedWords = (SuggestedWords) msg.obj;
232fa7075768da25341bf84e9f87bba09356961e2e8Jean Chalard                    latinIme.showSuggestionStrip(suggestedWords);
233908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                } else {
234908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                    latinIme.showGesturePreviewAndSuggestionStrip((SuggestedWords) msg.obj,
235908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                            msg.arg1 == ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT);
236908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                }
237f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka                break;
2386a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard            case MSG_RESUME_SUGGESTIONS:
239221df9e59aade0860624aeeb9b7b25311584c93aJean Chalard                latinIme.mInputLogic.restartSuggestionsOnWordTouchedByCursor(
2409444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                        latinIme.mSettings.getCurrent(), false /* forStartInput */,
2419444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                        latinIme.mKeyboardSwitcher.getCurrentKeyboardScriptId());
2429444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                break;
2439444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard            case MSG_RESUME_SUGGESTIONS_FOR_START_INPUT:
2449444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                latinIme.mInputLogic.restartSuggestionsOnWordTouchedByCursor(
2459444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                        latinIme.mSettings.getCurrent(), true /* forStartInput */,
24635c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                        latinIme.mKeyboardSwitcher.getCurrentKeyboardScriptId());
2476a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard                break;
248673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard            case MSG_REOPEN_DICTIONARIES:
2496345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard                // We need to re-evaluate the currently composing word in case the script has
2506345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard                // changed.
251fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard                postWaitForDictionaryLoad();
2521c0876dc49eee44170cb86ba3d78e759d5bbd573Jean Chalard                latinIme.resetDictionaryFacilitatorIfNecessary();
253673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard                break;
254a777c1c46073d7dc56590e58bdedb497bdfad182Jean Chalard            case MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED:
255c92c883fdf2287b49392692fa2e8d109dc26f785David Faden                final SuggestedWords suggestedWords = (SuggestedWords) msg.obj;
256a777c1c46073d7dc56590e58bdedb497bdfad182Jean Chalard                latinIme.mInputLogic.onUpdateTailBatchInputCompleted(
257a777c1c46073d7dc56590e58bdedb497bdfad182Jean Chalard                        latinIme.mSettings.getCurrent(),
258c92c883fdf2287b49392692fa2e8d109dc26f785David Faden                        suggestedWords, latinIme.mKeyboardSwitcher);
259c92c883fdf2287b49392692fa2e8d109dc26f785David Faden                latinIme.onTailBatchInputResultShown(suggestedWords);
260908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                break;
261f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard            case MSG_RESET_CACHES:
262ab80b41a0dee298837b1358457768ee5ac0fc79eJean Chalard                final SettingsValues settingsValues = latinIme.mSettings.getCurrent();
263dd31a2dedf3259662cacac9baad638ec10a0baebJean Chalard                if (latinIme.mInputLogic.retryResetCachesAndReturnSuccess(
264bea17c49ec23bf0f646cb548445c7756aa50d233Yohei Yukawa                        msg.arg1 == ARG1_TRUE /* tryResumeSuggestions */,
265ab80b41a0dee298837b1358457768ee5ac0fc79eJean Chalard                        msg.arg2 /* remainingTries */, this /* handler */)) {
266ab80b41a0dee298837b1358457768ee5ac0fc79eJean Chalard                    // If we were able to reset the caches, then we can reload the keyboard.
267ab80b41a0dee298837b1358457768ee5ac0fc79eJean Chalard                    // Otherwise, we'll do it when we can.
268ab80b41a0dee298837b1358457768ee5ac0fc79eJean Chalard                    latinIme.mKeyboardSwitcher.loadKeyboard(latinIme.getCurrentInputEditorInfo(),
269f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard                            settingsValues, latinIme.getCurrentAutoCapsState(),
27026611120c9083ffc342b4e0f8c78a9aef2b6db2eJean Chalard                            latinIme.getCurrentRecapitalizeState());
271ab80b41a0dee298837b1358457768ee5ac0fc79eJean Chalard                }
272f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard                break;
273fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            case MSG_WAIT_FOR_DICTIONARY_LOAD:
274fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard                Log.i(TAG, "Timeout waiting for dictionary load");
275fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard                break;
2767b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu            case MSG_DEALLOCATE_MEMORY:
2777b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                latinIme.deallocateMemory();
2787b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                break;
279809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa            case MSG_SWITCH_LANGUAGE_AUTOMATICALLY:
280809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa                latinIme.switchLanguage((InputMethodSubtype)msg.obj);
281809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa                break;
282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
284d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
285b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard        public void postUpdateSuggestionStrip(final int inputStyle) {
286b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP, inputStyle,
287a61b7245b030395451b4c42ec218a946aa95e030Yohei Yukawa                    0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions);
288d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
289d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
290673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        public void postReopenDictionaries() {
291673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard            sendMessage(obtainMessage(MSG_REOPEN_DICTIONARIES));
292673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        }
293673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard
2949444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard        private void postResumeSuggestionsInternal(final boolean shouldDelay,
2959444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                final boolean forStartInput) {
29698534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            final LatinIME latinIme = getOwnerInstance();
29798534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            if (latinIme == null) {
29898534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                return;
29998534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            }
300a61b7245b030395451b4c42ec218a946aa95e030Yohei Yukawa            if (!latinIme.mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()) {
301ac6dfaf80bb280cbc9afb2d6e697379b3fd1f373Jean Chalard                return;
302ac6dfaf80bb280cbc9afb2d6e697379b3fd1f373Jean Chalard            }
3039f9cc032773a528b4eb6e036db0c37ff45385cceJean Chalard            removeMessages(MSG_RESUME_SUGGESTIONS);
3049444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard            removeMessages(MSG_RESUME_SUGGESTIONS_FOR_START_INPUT);
3059444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard            final int message = forStartInput ? MSG_RESUME_SUGGESTIONS_FOR_START_INPUT
3069444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                    : MSG_RESUME_SUGGESTIONS;
307fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            if (shouldDelay) {
3089444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                sendMessageDelayed(obtainMessage(message),
3094c90df7e5b916e1d9e48e6902a8d0e884ee44673Jean Chalard                        mDelayInMillisecondsToUpdateSuggestions);
310fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            } else {
3119444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                sendMessage(obtainMessage(message));
312fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            }
3136a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard        }
3146a114fa700d3ca73c608e1291b74bbbdd5a1a7b7Jean Chalard
3159444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard        public void postResumeSuggestions(final boolean shouldDelay) {
3169444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard            postResumeSuggestionsInternal(shouldDelay, false /* forStartInput */);
3179444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard        }
3189444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard
3199444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard        public void postResumeSuggestionsForStartInput(final boolean shouldDelay) {
3209444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard            postResumeSuggestionsInternal(shouldDelay, true /* forStartInput */);
3219444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard        }
3229444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard
323772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard        public void postResetCaches(final boolean tryResumeSuggestions, final int remainingTries) {
324f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard            removeMessages(MSG_RESET_CACHES);
325f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard            sendMessage(obtainMessage(MSG_RESET_CACHES, tryResumeSuggestions ? 1 : 0,
326f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard                    remainingTries, null));
327f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard        }
328f1d8aa46f9172c2d8864d0d2161aa8220d036cc9Jean Chalard
329fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        public void postWaitForDictionaryLoad() {
330fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            sendMessageDelayed(obtainMessage(MSG_WAIT_FOR_DICTIONARY_LOAD),
3317b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                    DELAY_WAIT_FOR_DICTIONARY_LOAD_MILLIS);
332fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        }
333fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard
334fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        public void cancelWaitForDictionaryLoad() {
335fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            removeMessages(MSG_WAIT_FOR_DICTIONARY_LOAD);
336fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        }
337fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard
338fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        public boolean hasPendingWaitForDictionaryLoad() {
339fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            return hasMessages(MSG_WAIT_FOR_DICTIONARY_LOAD);
340fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        }
341fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard
342d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard        public void cancelUpdateSuggestionStrip() {
343dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard            removeMessages(MSG_UPDATE_SUGGESTION_STRIP);
344d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
345d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
346d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        public boolean hasPendingUpdateSuggestions() {
347dc1b84d96cf7fc4ee21cf7df8a12bc7913ffd64eJean Chalard            return hasMessages(MSG_UPDATE_SUGGESTION_STRIP);
348d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
349d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
350673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        public boolean hasPendingReopenDictionaries() {
351673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard            return hasMessages(MSG_REOPEN_DICTIONARIES);
352673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        }
353673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard
354beb08b398fa73a26f2d42d6feec87e34a96ca2d9Tadashi G. Takaoka        public void postUpdateShiftState() {
355d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SHIFT_STATE);
356a61b7245b030395451b4c42ec218a946aa95e030Yohei Yukawa            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
357a61b7245b030395451b4c42ec218a946aa95e030Yohei Yukawa                    mDelayInMillisecondsToUpdateShiftState);
358d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        }
359d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka
3607b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        public void postDeallocateMemory() {
3617b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu            sendMessageDelayed(obtainMessage(MSG_DEALLOCATE_MEMORY),
3627b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                    DELAY_DEALLOCATE_MEMORY_MILLIS);
3637b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        }
3647b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu
3657b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        public void cancelDeallocateMemory() {
3667b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu            removeMessages(MSG_DEALLOCATE_MEMORY);
3677b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        }
3687b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu
3697b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        public boolean hasPendingDeallocateMemory() {
3707b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu            return hasMessages(MSG_DEALLOCATE_MEMORY);
3717b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        }
3727b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu
3732fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        @UsedForTesting
3742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        public void removeAllMessages() {
3752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            for (int i = 0; i <= MSG_LAST; ++i) {
3762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                removeMessages(i);
3772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            }
3782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
3792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
380f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        public void showGesturePreviewAndSuggestionStrip(final SuggestedWords suggestedWords,
381f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka                final boolean dismissGestureFloatingPreviewText) {
382f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka            removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
383f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka            final int arg1 = dismissGestureFloatingPreviewText
384908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                    ? ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT
385908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada                    : ARG1_SHOW_GESTURE_FLOATING_PREVIEW_TEXT;
386a469743e331e57e3a03354f95268e4addf93b0e8Yuichiro Hanada            obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP, arg1,
387084c9961f4ede347fbfb719ce1075a10b93867c3Jean Chalard                    ARG2_UNUSED, suggestedWords).sendToTarget();
388f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        }
389f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka
390908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada        public void showSuggestionStrip(final SuggestedWords suggestedWords) {
391908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada            removeMessages(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP);
392908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada            obtainMessage(MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP,
393084c9961f4ede347fbfb719ce1075a10b93867c3Jean Chalard                    ARG1_NOT_GESTURE_INPUT, ARG2_UNUSED, suggestedWords).sendToTarget();
394908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada        }
395908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada
396a777c1c46073d7dc56590e58bdedb497bdfad182Jean Chalard        public void showTailBatchInputResult(final SuggestedWords suggestedWords) {
397a777c1c46073d7dc56590e58bdedb497bdfad182Jean Chalard            obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget();
398908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada        }
399908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada
400809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        public void postSwitchLanguage(final InputMethodSubtype subtype) {
401809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa            obtainMessage(MSG_SWITCH_LANGUAGE_AUTOMATICALLY, subtype).sendToTarget();
402809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        }
403809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa
40459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        // Working variables for the following methods.
40559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mIsOrientationChanging;
4065fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard        private boolean mPendingSuccessiveImsCallback;
40759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mHasPendingStartInput;
40859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mHasPendingFinishInputView;
40959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private boolean mHasPendingFinishInput;
410e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka        private EditorInfo mAppliedEditorInfo;
41159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
41259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void startOrientationChanging() {
413dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka            removeMessages(MSG_PENDING_IMS_CALLBACK);
414dd25e4fa2c7dd1e32a9e6f5fd21f54214919ef20Tadashi G. Takaoka            resetPendingImsCallback();
41559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mIsOrientationChanging = true;
4162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            final LatinIME latinIme = getOwnerInstance();
41798534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            if (latinIme == null) {
41898534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                return;
41998534dc065a828525129dc23aaca3ebd8834514cKen Wakasa            }
420f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka            if (latinIme.isInputViewShown()) {
421f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka                latinIme.mKeyboardSwitcher.saveKeyboardState();
422f2c9a88887a303f3df8bee60788870946dfa55f7Tadashi G. Takaoka            }
42359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
42459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
42559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        private void resetPendingImsCallback() {
42659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mHasPendingFinishInputView = false;
42759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mHasPendingFinishInput = false;
42859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            mHasPendingStartInput = false;
42959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
43059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
431f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        private void executePendingImsCallback(final LatinIME latinIme, final EditorInfo editorInfo,
43259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                boolean restarting) {
43312ff7da19df29511e489f426f372300a674f756aKen Wakasa            if (mHasPendingFinishInputView) {
43459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onFinishInputViewInternal(mHasPendingFinishInput);
43512ff7da19df29511e489f426f372300a674f756aKen Wakasa            }
43612ff7da19df29511e489f426f372300a674f756aKen Wakasa            if (mHasPendingFinishInput) {
43759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                latinIme.onFinishInputInternal();
43812ff7da19df29511e489f426f372300a674f756aKen Wakasa            }
43912ff7da19df29511e489f426f372300a674f756aKen Wakasa            if (mHasPendingStartInput) {
440e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                latinIme.onStartInputInternal(editorInfo, restarting);
44112ff7da19df29511e489f426f372300a674f756aKen Wakasa            }
44259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            resetPendingImsCallback();
44359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
44459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
445f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        public void onStartInput(final EditorInfo editorInfo, final boolean restarting) {
44659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
44759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                // Typically this is the second onStartInput after orientation changed.
44859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                mHasPendingStartInput = true;
44959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            } else {
45059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                if (mIsOrientationChanging && restarting) {
45159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                    // This is the first onStartInput after orientation changed.
45259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                    mIsOrientationChanging = false;
4535fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard                    mPendingSuccessiveImsCallback = true;
45459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                }
4552fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                final LatinIME latinIme = getOwnerInstance();
45698534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                if (latinIme != null) {
45798534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    executePendingImsCallback(latinIme, editorInfo, restarting);
45898534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    latinIme.onStartInputInternal(editorInfo, restarting);
45998534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                }
460055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            }
461055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        }
462055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
463f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) {
4646b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)
4656b7100fecaaaf0e8e42c4d2ccebac165e89e79bfTadashi G. Takaoka                    && KeyboardId.equivalentEditorInfoForKeyboard(editorInfo, mAppliedEditorInfo)) {
466e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                // Typically this is the second onStartInputView after orientation changed.
467e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                resetPendingImsCallback();
468e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka            } else {
4695fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard                if (mPendingSuccessiveImsCallback) {
470e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                    // This is the first onStartInputView after orientation changed.
4715fd11a7f3367d51cea8dc83fb9675c93d82a2e4eJean Chalard                    mPendingSuccessiveImsCallback = false;
472e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                    resetPendingImsCallback();
473e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                    sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK),
4747b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                            PENDING_IMS_CALLBACK_DURATION_MILLIS);
475e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka                }
4762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                final LatinIME latinIme = getOwnerInstance();
47798534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                if (latinIme != null) {
47898534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    executePendingImsCallback(latinIme, editorInfo, restarting);
47998534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    latinIme.onStartInputViewInternal(editorInfo, restarting);
48098534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    mAppliedEditorInfo = editorInfo;
48198534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                }
4827b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                cancelDeallocateMemory();
483e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka            }
48459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        }
48559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
486f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        public void onFinishInputView(final boolean finishingInput) {
48759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
48859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                // Typically this is the first onFinishInputView after orientation changed.
48959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                mHasPendingFinishInputView = true;
49059f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            } else {
4912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                final LatinIME latinIme = getOwnerInstance();
49298534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                if (latinIme != null) {
49398534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    latinIme.onFinishInputViewInternal(finishingInput);
49498534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    mAppliedEditorInfo = null;
49598534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                }
4967b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                if (!hasPendingDeallocateMemory()) {
4977b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                    postDeallocateMemory();
4987b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu                }
49938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka            }
50038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka        }
501ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka
50259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        public void onFinishInput() {
50359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            if (hasMessages(MSG_PENDING_IMS_CALLBACK)) {
50459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                // Typically this is the first onFinishInput after orientation changed.
50559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka                mHasPendingFinishInput = true;
50659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka            } else {
5072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                final LatinIME latinIme = getOwnerInstance();
50898534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                if (latinIme != null) {
50998534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    executePendingImsCallback(latinIme, null, false);
51098534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                    latinIme.onFinishInputInternal();
51198534dc065a828525129dc23aaca3ebd8834514cKen Wakasa                }
512ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka            }
513ffd156c77e93a54b704780b46886ba597d1c77cbTadashi G. Takaoka        }
51438f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka    }
51538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
5161931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    static final class SubtypeState {
5171931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        private InputMethodSubtype mLastActiveSubtype;
5186345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard        private boolean mCurrentSubtypeHasBeenUsed;
5191931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka
5206345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard        public void setCurrentSubtypeHasBeenUsed() {
5216345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard            mCurrentSubtypeHasBeenUsed = true;
5221931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        }
5231931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka
5241931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        public void switchSubtype(final IBinder token, final RichInputMethodManager richImm) {
5251931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka            final InputMethodSubtype currentSubtype = richImm.getInputMethodManager()
5261931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                    .getCurrentInputMethodSubtype();
5271931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka            final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
5286345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard            final boolean currentSubtypeHasBeenUsed = mCurrentSubtypeHasBeenUsed;
5296345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard            if (currentSubtypeHasBeenUsed) {
5301931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                mLastActiveSubtype = currentSubtype;
5316345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard                mCurrentSubtypeHasBeenUsed = false;
5321931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka            }
5336345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard            if (currentSubtypeHasBeenUsed
5341931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                    && richImm.checkIfSubtypeBelongsToThisImeAndEnabled(lastActiveSubtype)
5351931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                    && !currentSubtype.equals(lastActiveSubtype)) {
5361931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                richImm.setInputMethodAndSubtype(token, lastActiveSubtype);
5371931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                return;
5381931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka            }
5391931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka            richImm.switchToNextInputMethod(token, true /* onlyCurrentIme */);
5401931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        }
5411931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    }
5421931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka
543bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasa    // Loading the native library eagerly to avoid unexpected UnsatisfiedLinkError at the initial
544bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasa    // JNI call as much as possible.
545bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasa    static {
546bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasa        JniUtils.loadNativeLibrary();
547bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasa    }
548bfaf349c3554e11af8227a5f0807a74107a93069Ken Wakasa
54989ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard    public LatinIME() {
55089ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard        super();
551ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka        mSettings = Settings.getInstance();
55289ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
553aabb3512791979a00c0ab50c0be808f46d18cbe6Jatin Matani        mStatsUtilsManager = StatsUtilsManager.getInstance();
554fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa        mIsHardwareAcceleratedDrawingEnabled =
555fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa                InputMethodServiceCompatUtils.enableHardwareAcceleration(this);
556fb955693d4bb0c8d39092250a4208e385b8a31a7Ken Wakasa        Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled);
55789ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard    }
55889ffb212b469531db4a616afb9bb7ba6d2a56b50Jean Chalard
5597e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
5607e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    public void onCreate() {
561ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka        Settings.init(this);
5622dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaoka        DebugFlags.init(PreferenceManager.getDefaultSharedPreferences(this));
563f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka        RichInputMethodManager.init(this);
56485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        mRichImm = RichInputMethodManager.getInstance();
565f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka        KeyboardSwitcher.init(this);
566b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        AudioAndHapticFeedbackManager.init(this);
5672ac5988f84b5c38d313951a3d7faddebf5f25e04Tadashi G. Takaoka        AccessibilityUtils.init(this);
5680103d75aaf0472051147b047fc68fe8ae6881de5Chieu Nguyen        mStatsUtilsManager.onCreate(this /* context */, mDictionaryFacilitator);
569923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onCreate();
570363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
57110dff76856a98b6eec86a53d3d07fdc9708037b7Tadashi G. Takaoka        mHandler.onCreate();
572363cd6ef0f8f8af41a01964a2f0e800f9305d3a2Tadashi G. Takaoka
5731c0876dc49eee44170cb86ba3d78e759d5bbd573Jean Chalard        // TODO: Resolve mutual dependencies of {@link #loadSettings()} and
5741c0876dc49eee44170cb86ba3d78e759d5bbd573Jean Chalard        // {@link #resetDictionaryFacilitatorIfNecessary()}.
57528f36d68afe8d323d1032d0e03fe3013449e21feKen Wakasa        loadSettings();
5761c0876dc49eee44170cb86ba3d78e759d5bbd573Jean Chalard        resetDictionaryFacilitatorIfNecessary();
577979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5782b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka        // Register to receive ringer mode change.
579123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka        final IntentFilter filter = new IntentFilter();
58021af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
5812b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka        registerReceiver(mRingerModeChangeReceiver, filter);
582cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
5832b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka        // Register to receive installation and removal of a dictionary pack.
584efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        final IntentFilter packageFilter = new IntentFilter();
585efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
586efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
587efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        packageFilter.addDataScheme(SCHEME_PACKAGE);
588efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        registerReceiver(mDictionaryPackInstallReceiver, packageFilter);
589efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge
590efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        final IntentFilter newDictFilter = new IntentFilter();
591efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        newDictFilter.addAction(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION);
592efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        registerReceiver(mDictionaryPackInstallReceiver, newDictFilter);
593908fc4f1c324eac2a42a69680dbd196c5b9492f6Yuichiro Hanada
59436c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi        final IntentFilter dictDumpFilter = new IntentFilter();
59536c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi        dictDumpFilter.addAction(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION);
59636c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi        registerReceiver(mDictionaryDumpBroadcastReceiver, dictDumpFilter);
59736c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi
598698b19ef35d1d865943ec9d9ee05f8f0e66dc3f8Mohammadinamul Sheik        StatsUtils.onCreate(mSettings.getCurrent(), mRichImm);
599923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
60036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
60117c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    // Has to be package-visible for unit tests
60215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting
6039fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka    void loadSettings() {
604107fb4c476779df16be23e245547253978c197acDan Zivkovic        final Locale locale = mRichImm.getCurrentSubtypeLocale();
6051404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard        final EditorInfo editorInfo = getCurrentInputEditorInfo();
6063ca65c8fd56724a7b4b3440bccf613e5a1a17513Tadashi G. Takaoka        final InputAttributes inputAttributes = new InputAttributes(
6073ca65c8fd56724a7b4b3440bccf613e5a1a17513Tadashi G. Takaoka                editorInfo, isFullscreenMode(), getPackageName());
608107fb4c476779df16be23e245547253978c197acDan Zivkovic        mSettings.loadSettings(this, locale, inputAttributes);
609f1457e7a221082688b6399853e84e77948633c7bKeisuke Kuroyanagi        final SettingsValues currentSettingsValues = mSettings.getCurrent();
610e9926b0d11d481c6534c059384c9a5a858ebdaaeKeisuke Kuroyanagi        AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(currentSettingsValues);
611e9926b0d11d481c6534c059384c9a5a858ebdaaeKeisuke Kuroyanagi        // This method is called on startup and language switch, before the new layout has
612e9926b0d11d481c6534c059384c9a5a858ebdaaeKeisuke Kuroyanagi        // been displayed. Opening dictionaries never affects responsivity as dictionaries are
613e9926b0d11d481c6534c059384c9a5a858ebdaaeKeisuke Kuroyanagi        // asynchronously loaded.
614adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi        if (!mHandler.hasPendingReopenDictionaries()) {
615107fb4c476779df16be23e245547253978c197acDan Zivkovic            resetDictionaryFacilitator(locale);
616f1457e7a221082688b6399853e84e77948633c7bKeisuke Kuroyanagi        }
617d7a22c8439c77f2bf81b5dc60d58cf65d129da81Keisuke Kuroyanagi        refreshPersonalizationDictionarySession(currentSettingsValues);
618bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani        resetDictionaryFacilitatorIfNecessary();
6190103d75aaf0472051147b047fc68fe8ae6881de5Chieu Nguyen        mStatsUtilsManager.onLoadSettings(this /* context */, currentSettingsValues);
6209f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi    }
6219f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi
622d7a22c8439c77f2bf81b5dc60d58cf65d129da81Keisuke Kuroyanagi    private void refreshPersonalizationDictionarySession(
623d7a22c8439c77f2bf81b5dc60d58cf65d129da81Keisuke Kuroyanagi            final SettingsValues currentSettingsValues) {
6249a289da4e6ea40417422a540e821069d5d6e4a82Dan Zivkovic        if (!currentSettingsValues.mUsePersonalizedDicts) {
625d102eb80da07de6b9541c3e8d767441d84257b8dKeisuke Kuroyanagi            // Remove user history dictionaries.
626d102eb80da07de6b9541c3e8d767441d84257b8dKeisuke Kuroyanagi            PersonalizationHelper.removeAllUserHistoryDictionaries(this);
627bdd6c995cee664e6cd025235be2d00fc439afb1dDan Zivkovic            mDictionaryFacilitator.clearUserHistoryDictionary(this);
628d102eb80da07de6b9541c3e8d767441d84257b8dKeisuke Kuroyanagi        }
62917c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard    }
63017c7ffeb1e10348227c5dff1c319d2099c1b5d0eJean Chalard
6318335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka    // Note that this method is called from a non-UI thread.
632369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka    @Override
633f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onUpdateMainDictionaryAvailability(final boolean isMainDictionaryAvailable) {
6348335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
6358335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        if (mainKeyboardView != null) {
6368335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka            mainKeyboardView.setMainDictionaryAvailability(isMainDictionaryAvailable);
6378335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka        }
638fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        if (mHandler.hasPendingWaitForDictionaryLoad()) {
639fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard            mHandler.cancelWaitForDictionaryLoad();
6404c90df7e5b916e1d9e48e6902a8d0e884ee44673Jean Chalard            mHandler.postResumeSuggestions(false /* shouldDelay */);
641fa4c59f9b6663e5de08692f853e968603dfc10e9Jean Chalard        }
642369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka    }
643369e54cc338d8115d63138663b882f56208d7ec3Tadashi G. Takaoka
6445f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void resetDictionaryFacilitatorIfNecessary() {
645107fb4c476779df16be23e245547253978c197acDan Zivkovic        final Locale subtypeSwitcherLocale = mRichImm.getCurrentSubtypeLocale();
646107fb4c476779df16be23e245547253978c197acDan Zivkovic        final Locale subtypeLocale;
647107fb4c476779df16be23e245547253978c197acDan Zivkovic        if (subtypeSwitcherLocale == null) {
64843a8a0c5270a54742dcfff9dc441cf2747cb4e06Jean Chalard            // This happens in very rare corner cases - for example, immediately after a switch
64943a8a0c5270a54742dcfff9dc441cf2747cb4e06Jean Chalard            // to LatinIME has been requested, about a frame later another switch happens. In this
65043a8a0c5270a54742dcfff9dc441cf2747cb4e06Jean Chalard            // case, we are about to go down but we still don't know it, however the system tells
651bc051a561f1766e5cea2866468c769f5cb346ffbJean Chalard            // us there is no current subtype.
65243a8a0c5270a54742dcfff9dc441cf2747cb4e06Jean Chalard            Log.e(TAG, "System is reporting no current subtype.");
653107fb4c476779df16be23e245547253978c197acDan Zivkovic            subtypeLocale = getResources().getConfiguration().locale;
65443a8a0c5270a54742dcfff9dc441cf2747cb4e06Jean Chalard        } else {
655107fb4c476779df16be23e245547253978c197acDan Zivkovic            subtypeLocale = subtypeSwitcherLocale;
656107fb4c476779df16be23e245547253978c197acDan Zivkovic        }
657107fb4c476779df16be23e245547253978c197acDan Zivkovic        if (mDictionaryFacilitator.isForLocale(subtypeLocale)
658107fb4c476779df16be23e245547253978c197acDan Zivkovic                && mDictionaryFacilitator.isForAccount(mSettings.getCurrent().mAccount)) {
659107fb4c476779df16be23e245547253978c197acDan Zivkovic            return;
66043a8a0c5270a54742dcfff9dc441cf2747cb4e06Jean Chalard        }
661107fb4c476779df16be23e245547253978c197acDan Zivkovic        resetDictionaryFacilitator(subtypeLocale);
6629f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi    }
66336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
664adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi    /**
665107fb4c476779df16be23e245547253978c197acDan Zivkovic     * Reset the facilitator by loading dictionaries for the given locale and
666bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani     * the current settings values.
667adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi     *
668107fb4c476779df16be23e245547253978c197acDan Zivkovic     * @param locale the locale
669adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi     */
670bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani    // TODO: make sure the current settings always have the right locales, and read from them.
671107fb4c476779df16be23e245547253978c197acDan Zivkovic    private void resetDictionaryFacilitator(final Locale locale) {
672adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi        final SettingsValues settingsValues = mSettings.getCurrent();
673107fb4c476779df16be23e245547253978c197acDan Zivkovic        mDictionaryFacilitator.resetDictionaries(this /* context */, locale,
674adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi                settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
675bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani                false /* forceReloadMainDictionary */,
676d6a8adcb044dd8b73a1c96776a835b411a978b46Dan Zivkovic                settingsValues.mAccount, "" /* dictNamePrefix */,
677bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani                this /* DictionaryInitializationListener */);
678ab661e3ef886a36b02fe094864ae4be6a3260f71Tadashi G. Takaoka        if (settingsValues.mAutoCorrectionEnabledPerUserSettings) {
679adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi            mInputLogic.mSuggest.setAutoCorrectionThreshold(
680adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi                    settingsValues.mAutoCorrectionThreshold);
68178ab80844b4f8e0369f4e86b2a02208197f9bd34Tadashi G. Takaoka        }
68256577461d63ad3618598ceddfb9a73b797917061Jean Chalard        mInputLogic.mSuggest.setPlausibilityThreshold(settingsValues.mPlausibilityThreshold);
6839f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi    }
6849f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi
685adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi    /**
686adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi     * Reset suggest by loading the main dictionary of the current locale.
687adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi     */
6889f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi    /* package private */ void resetSuggestMainDict() {
689adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi        final SettingsValues settingsValues = mSettings.getCurrent();
690a1035be6d877cafda95b2761f9697474b79deeb8Keisuke Kuroyanagi        mDictionaryFacilitator.resetDictionaries(this /* context */,
691107fb4c476779df16be23e245547253978c197acDan Zivkovic                mDictionaryFacilitator.getLocale(), settingsValues.mUseContactsDict,
692bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani                settingsValues.mUsePersonalizedDicts,
693bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani                true /* forceReloadMainDictionary */,
694d6a8adcb044dd8b73a1c96776a835b411a978b46Dan Zivkovic                settingsValues.mAccount, "" /* dictNamePrefix */,
695bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani                this /* DictionaryInitializationListener */);
696cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard    }
697cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard
698466741d8a78965b8509bf527344f289e50873092Mike LeBeau    @Override
699466741d8a78965b8509bf527344f289e50873092Mike LeBeau    public void onDestroy() {
700a1035be6d877cafda95b2761f9697474b79deeb8Keisuke Kuroyanagi        mDictionaryFacilitator.closeDictionaries();
701ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka        mSettings.onDestroy();
7022b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka        unregisterReceiver(mRingerModeChangeReceiver);
703efd26bb3192722c2980098a6f36dff6006e8896aKurt Partridge        unregisterReceiver(mDictionaryPackInstallReceiver);
704f2d15d6956c06543fc4c09591a35d35f823f8f0dKeisuke Kuroyanagi        unregisterReceiver(mDictionaryDumpBroadcastReceiver);
7052b69244555af209b52181777cdd751cbb543bd93Jatin Matani        mStatsUtilsManager.onDestroy(this /* context */);
706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onDestroy();
707923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
708923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
7094370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard    @UsedForTesting
7104370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard    public void recycle() {
71166e509b1d4a8f41a7e4d6e26dfa0dd9995e945a9Jean Chalard        unregisterReceiver(mDictionaryPackInstallReceiver);
71266e509b1d4a8f41a7e4d6e26dfa0dd9995e945a9Jean Chalard        unregisterReceiver(mDictionaryDumpBroadcastReceiver);
7132b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka        unregisterReceiver(mRingerModeChangeReceiver);
7144370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard        mInputLogic.recycle();
7154370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard    }
7164370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard
7171fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic    private boolean isImeSuppressedByHardwareKeyboard() {
7181fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
71948adccf34910e694b8751b8dfdb76b3c7281c1e8Keisuke Kuroyanagi        return !onEvaluateInputViewShown() && switcher.isImeSuppressedByHardwareKeyboard(
7201fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic                mSettings.getCurrent(), switcher.getKeyboardSwitchState());
7211fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic    }
7221fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic
723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
724f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onConfigurationChanged(final Configuration conf) {
7259395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        SettingsValues settingsValues = mSettings.getCurrent();
726aa161eb371d8042ef4c1f9207648b3aeacb65e4eJean Chalard        if (settingsValues.mDisplayOrientation != conf.orientation) {
727f94df382fb3f73c03cfef5f0a28856bf3f1c73daTadashi G. Takaoka            mHandler.startOrientationChanging();
72828ebbd481ad38f41211d853bf5eb39b36842be36Jean Chalard            mInputLogic.onOrientationChange(mSettings.getCurrent());
729b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
7309395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        if (settingsValues.mHasHardwareKeyboard != Settings.readHasHardwareKeyboard(conf)) {
7319395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // If the state of having a hardware keyboard changed, then we want to reload the
7329395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // settings to adjust for that.
7339395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // TODO: we should probably do this unconditionally here, rather than only when we
7349395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // have a change in hardware keyboard configuration.
7359395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            loadSettings();
7369395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            settingsValues = mSettings.getCurrent();
7371fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic            if (isImeSuppressedByHardwareKeyboard()) {
7389395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // We call cleanupInternalStateForFinishInput() because it's the right thing to do;
7399395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // however, it seems at the moment the framework is passing us a seemingly valid
7409395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // but actually non-functional InputConnection object. So if this bug ever gets
7419395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // fixed we'll be able to remove the composition, but until it is this code is
7429395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // actually not doing much.
7439395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                cleanupInternalStateForFinishInput();
7449395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            }
7459395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        }
746923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onConfigurationChanged(conf);
747923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
748b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
749923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
750923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public View onCreateInputView() {
7511c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani        StatsUtils.onCreateInputView();
752622d6a5b1b3d6a9140765b868abf1cdf412bc4f3Tadashi G. Takaoka        return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled);
7536c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    }
7546c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka
7556c4add55f94ff729ef1aa35c4f8df3b086344f8aTadashi G. Takaoka    @Override
756c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa    public void setInputView(final View view) {
757c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa        super.setInputView(view);
7588fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka        mInputView = view;
75915480481be790c913b0117d0841565efd399cd01Tadashi G. Takaoka        mInsetsUpdater = ViewOutlineProviderCompatUtils.setInsetsOutlineProvider(view);
76096d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        updateSoftInputWindowLayoutParameters();
761c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa        mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view);
76212ff7da19df29511e489f426f372300a674f756aKen Wakasa        if (hasSuggestionStripView()) {
763c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa            mSuggestionStripView.setListener(this, view);
7642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        }
765923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
766923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
767923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
768f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void setCandidatesView(final View view) {
769c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        // To ensure that CandidatesView will never be set.
770923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
771923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
772a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker    @Override
773f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onStartInput(final EditorInfo editorInfo, final boolean restarting) {
774e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka        mHandler.onStartInput(editorInfo, restarting);
77559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
77659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
77759f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    @Override
778f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onStartInputView(final EditorInfo editorInfo, final boolean restarting) {
779e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka        mHandler.onStartInputView(editorInfo, restarting);
7806a6137325b82d3dc6ca09e7d918ea50e50c9ac03Jatin Matani        mStatsUtilsManager.onStartInputView();
78159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
78259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
78359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    @Override
784f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onFinishInputView(final boolean finishingInput) {
7851c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani        StatsUtils.onFinishInputView();
78659f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        mHandler.onFinishInputView(finishingInput);
7876a6137325b82d3dc6ca09e7d918ea50e50c9ac03Jatin Matani        mStatsUtilsManager.onFinishInputView();
788c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER;
78959f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
79038f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka
79159f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    @Override
79259f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    public void onFinishInput() {
79359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka        mHandler.onFinishInput();
79459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
79559f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
7969cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka    @Override
797f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) {
7984f96bb4520de3610ae94da96b98e507ca7b76362satok        // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
7994f96bb4520de3610ae94da96b98e507ca7b76362satok        // is not guaranteed. It may even be called at the same time on a different thread.
80040833d2dd79b193efd33036417ad1909273d9f7dChieu Nguyen        InputMethodSubtype oldSubtype = mRichImm.getCurrentSubtype().getRawSubtype();
80140833d2dd79b193efd33036417ad1909273d9f7dChieu Nguyen        StatsUtils.onSubtypeChanged(oldSubtype, subtype);
8024486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka        mRichImm.onSubtypeChanged(subtype);
80329200b0abe1d65aa2f9ddefd247ab91563d666f8Yohei Yukawa        mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
80429200b0abe1d65aa2f9ddefd247ab91563d666f8Yohei Yukawa                mSettings.getCurrent());
8059fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka        loadKeyboard();
8069cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka    }
8079cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka
8085f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) {
809e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka        super.onStartInput(editorInfo, restarting);
810809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa
811809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        // If the primary hint language does not match the current subtype language, then try
812809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        // to switch to the primary hint language.
813809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        // TODO: Support all the locales in EditorInfo#hintLocales.
814809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        final Locale primaryHintLocale = EditorInfoCompatUtils.getPrimaryHintLocale(editorInfo);
815809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        if (primaryHintLocale == null) {
816809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa            return;
817809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        }
818809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        final InputMethodSubtype newSubtype = mRichImm.findSubtypeByLocale(primaryHintLocale);
819809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        if (newSubtype == null || newSubtype.equals(mRichImm.getCurrentSubtype().getRawSubtype())) {
820809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa            return;
821809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        }
822809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        mHandler.postSwitchLanguage(newSubtype);
82359f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    }
82459f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka
8251cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka    @SuppressWarnings("deprecation")
8265f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void onStartInputViewInternal(final EditorInfo editorInfo, final boolean restarting) {
827e7eac906c0a14b644d457beeb73a407fa1b63673Tadashi G. Takaoka        super.onStartInputView(editorInfo, restarting);
828755b3d882f9d74ceaec7b59fe618dff3ad54f304Dan Zivkovic
829755b3d882f9d74ceaec7b59fe618dff3ad54f304Dan Zivkovic        mDictionaryFacilitator.onStartInput();
830c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        // Switch to the null consumer to handle cases leading to early exit below, for which we
831c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        // also wouldn't be consuming gesture data.
832c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER;
8334486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka        mRichImm.refreshSubtypeCaches();
83445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final KeyboardSwitcher switcher = mKeyboardSwitcher;
835db86a6f271e5ca446382061f219928c5eb6b9f01Tadashi G. Takaoka        switcher.updateKeyboardTheme();
83627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView();
8371f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard        // If we are starting input in a different text field from before, we'll have to reload
8381f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard        // settings, so currentSettingsValues can't be final.
8391f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard        SettingsValues currentSettingsValues = mSettings.getCurrent();
8408e09172df1bb176cc899940862c56bed9b9aec4esatok
841ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok        if (editorInfo == null) {
842ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok            Log.e(TAG, "Null EditorInfo in onStartInputView()");
8432dae79b1966a7970c25c8b79beec1c95c13f6c87Tadashi G. Takaoka            if (DebugFlags.DEBUG_ENABLED) {
844ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok                throw new NullPointerException("Null EditorInfo in onStartInputView()");
845ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok            }
846ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok            return;
847ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok        }
848edaa83bb32e7299b5bba2c42d703701c1e2a3d5bDan Zivkovic        if (DebugFlags.DEBUG_ENABLED) {
849ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok            Log.d(TAG, "onStartInputView: editorInfo:"
850ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok                    + String.format("inputType=0x%08x imeOptions=0x%08x",
851ca7ec2097ca6af1505c1e6aa8b81b6068ba46daesatok                            editorInfo.inputType, editorInfo.imeOptions));
852b6fb5eb391987f3e426649a892cdcbf781957f5asatok            Log.d(TAG, "All caps = "
853b6fb5eb391987f3e426649a892cdcbf781957f5asatok                    + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0)
854b6fb5eb391987f3e426649a892cdcbf781957f5asatok                    + ", sentence caps = "
855b6fb5eb391987f3e426649a892cdcbf781957f5asatok                    + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0)
856b6fb5eb391987f3e426649a892cdcbf781957f5asatok                    + ", word caps = "
857b6fb5eb391987f3e426649a892cdcbf781957f5asatok                    + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0));
858910b73127fa207dd26ec8124000262523b0aac0csatok        }
8593b4c1d30565c06a7f5a4c362002862e8bcb61f01Jean Chalard        Log.i(TAG, "Starting input. Cursor position = "
8603b4c1d30565c06a7f5a4c362002862e8bcb61f01Jean Chalard                + editorInfo.initialSelStart + "," + editorInfo.initialSelEnd);
861aa4b2c71270576f25e7c80a4b63a1956cec5f4e2Tadashi G. Takaoka        // TODO: Consolidate these checks with {@link InputAttributes}.
8621cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka        if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
86312ff7da19df29511e489f426f372300a674f756aKen Wakasa            Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions);
8641cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka            Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead");
8654f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka        }
8661cb08acaf3b4d58cbf4cb65f9fc3990b39e33f00Tadashi G. Takaoka        if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) {
86712ff7da19df29511e489f426f372300a674f756aKen Wakasa            Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions);
8684f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka            Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead");
8694f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka        }
8704f5c3a2898315ff41cc735a195cfeb2937f22f70Tadashi G. Takaoka
871923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // In landscape mode, this method gets called without the input view being created.
87227e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        if (mainKeyboardView == null) {
873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return;
874923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
876c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        // Update to a gesture consumer with the current editor and IME state.
877c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer = GestureConsumer.newInstance(editorInfo,
878c92c883fdf2287b49392692fa2e8d109dc26f785David Faden                mInputLogic.getPrivateCommandPerformer(),
879107fb4c476779df16be23e245547253978c197acDan Zivkovic                mRichImm.getCurrentSubtypeLocale(),
880c92c883fdf2287b49392692fa2e8d109dc26f785David Faden                switcher.getKeyboard());
881c92c883fdf2287b49392692fa2e8d109dc26f785David Faden
882b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        // Forward this event to the accessibility utilities, if enabled.
883b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        final AccessibilityUtils accessUtils = AccessibilityUtils.getInstance();
884b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        if (accessUtils.isTouchExplorationEnabled()) {
88505384933097c1e9c35e8be5c03757d072e5ffa46alanv            accessUtils.onStartInputViewInternal(mainKeyboardView, editorInfo, restarting);
886b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette        }
887b0c8db018d53b103dcb4b699be27a4e1a2c2f92cAlan Viverette
8881f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard        final boolean inputTypeChanged = !currentSettingsValues.isSameInputType(editorInfo);
889e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard        final boolean isDifferentTextField = !restarting || inputTypeChanged;
8901c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani
8911c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani        StatsUtils.onStartInputView(editorInfo.inputType,
8921c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani                Settings.getInstance().getCurrent().mDisplayOrientation,
8931c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani                !isDifferentTextField);
8941c45f9142bb2cf79aa7da29bc01f11195678aadaJatin Matani
895b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka        // The EditorInfo might have a flag that affects fullscreen mode.
896b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka        // Note: This call should be done by InputMethodService?
897b2b1eb5ca5a52648eea70920b9bd745b07d3ddfaTadashi G. Takaoka        updateFullscreenMode();
898c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
8999395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        // ALERT: settings have not been reloaded and there is a chance they may be stale.
9009395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        // In the practice, if it is, we should have gotten onConfigurationChanged so it should
9019395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        // be fine, but this is horribly confusing and must be fixed AS SOON AS POSSIBLE.
902772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard
9039395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        // In some cases the input connection has not been reset yet and we can't access it. In
9049395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        // this case we will need to call loadKeyboard() later, when it's accessible, so that we
9059395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        // can go into the correct mode, so we need to do some housekeeping here.
9069395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        final boolean needToCallLoadKeyboardLater;
907772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard        final Suggest suggest = mInputLogic.mSuggest;
9081fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        if (!isImeSuppressedByHardwareKeyboard()) {
9099395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // The app calling setText() has the effect of clearing the composing
9109395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // span, so we should reset our state unconditionally, even if restarting is true.
9119395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // We also tell the input logic about the combining rules for the current subtype, so
9129395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // it can adjust its combiners if needed.
9137fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka            mInputLogic.startInput(mRichImm.getCombiningRulesExtraValueOfCurrentSubtype(),
9149395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                    currentSettingsValues);
9159395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard
9161c0876dc49eee44170cb86ba3d78e759d5bbd573Jean Chalard            resetDictionaryFacilitatorIfNecessary();
9179395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard
9189395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // TODO[IL]: Can the following be moved to InputLogic#startInput?
9199395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            if (!mInputLogic.mConnection.resetCachesUponCursorMoveAndReturnSuccess(
9209395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                    editorInfo.initialSelStart, editorInfo.initialSelEnd,
9219395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                    false /* shouldFinishComposition */)) {
9229395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // Sometimes, while rotating, for some reason the framework tells the app we are not
9239395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // connected to it and that means we can't refresh the cache. In this case, schedule
9249395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // a refresh later.
9259395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // We try resetting the caches up to 5 times before giving up.
9269395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                mHandler.postResetCaches(isDifferentTextField, 5 /* remainingTries */);
9279395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // mLastSelection{Start,End} are reset later in this method, no need to do it here
9289395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                needToCallLoadKeyboardLater = true;
9299395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            } else {
93038144047ea3985c9345e7fbe6bb3aafbeaea5f06Jean Chalard                // When rotating, and when input is starting again in a field from where the focus
93138144047ea3985c9345e7fbe6bb3aafbeaea5f06Jean Chalard                // didn't move (the keyboard having been closed with the back key),
93238144047ea3985c9345e7fbe6bb3aafbeaea5f06Jean Chalard                // initialSelStart and initialSelEnd sometimes are lying. Make a best effort to
93338144047ea3985c9345e7fbe6bb3aafbeaea5f06Jean Chalard                // work around this bug.
9349395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                mInputLogic.mConnection.tryFixLyingCursorPosition();
9359444d70514cfa11e88380e653bea3b4a6c205151Jean Chalard                mHandler.postResumeSuggestionsForStartInput(true /* shouldDelay */);
9369395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                needToCallLoadKeyboardLater = false;
9379395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            }
938772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard        } else {
9399395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            // If we have a hardware keyboard we don't need to call loadKeyboard later anyway.
9409395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            needToCallLoadKeyboardLater = false;
941772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard        }
942772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard
9431f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard        if (isDifferentTextField ||
9441f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard                !currentSettingsValues.hasSameOrientation(getResources().getConfiguration())) {
945772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard            loadSettings();
946772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard        }
947e234aed4288efd7b4336f3755a958c25a1540b98Jean Chalard        if (isDifferentTextField) {
94827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka            mainKeyboardView.closing();
9491f3d89c2af645a85d863083ff7956a5ca7e1abc7Jean Chalard            currentSettingsValues = mSettings.getCurrent();
95074bcc911ea477415edc19eca829dbba9ab1b2464Jean Chalard
951772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard            if (currentSettingsValues.mAutoCorrectionEnabledPerUserSettings) {
952772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard                suggest.setAutoCorrectionThreshold(
953772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard                        currentSettingsValues.mAutoCorrectionThreshold);
954772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard            }
95556577461d63ad3618598ceddfb9a73b797917061Jean Chalard            suggest.setPlausibilityThreshold(currentSettingsValues.mPlausibilityThreshold);
956772a8019efbc280f6228fc2d7baca66f5dee755eJean Chalard
957f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard            switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(),
958f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard                    getCurrentRecapitalizeState());
9599395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard            if (needToCallLoadKeyboardLater) {
9609395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // If we need to call loadKeyboard again later, we need to save its state now. The
9619395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard                // later call will be done in #retryResetCaches.
962482aa129e4fa104708601672c9eff674d0a79cd4Jean Chalard                switcher.saveKeyboardState();
9633c4e8cb693ce584ea1f87e354430c069cdd3da39Jean Chalard            }
9645d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa        } else if (restarting) {
9655d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa            // TODO: Come up with a more comprehensive way to reset the keyboard layout when
9665d2556b93286f5f1d7d829b586b84a8b7ae55743Ken Wakasa            // a keyboard layout set doesn't get reloaded in this method.
967f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard            switcher.resetKeyboardStateToAlphabet(getCurrentAutoCapsState(),
968f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard                    getCurrentRecapitalizeState());
969d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka            // In apps like Talk, we come here when the text is sent and the field gets emptied and
970d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka            // we need to re-evaluate the shift state, but not the whole layout which would be
971d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka            // disruptive.
972d0725a68421203ae42d78ceed57767a5204e858eTadashi G. Takaoka            // Space state must be updated before calling updateShiftState
9738ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard            switcher.requestUpdatingShiftState(getCurrentAutoCapsState(),
9748ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard                    getCurrentRecapitalizeState());
975aa906c36aa31f51a38083e337f4307b49f133054Jean Chalard        }
976affdd364232549d2062fc180f924f5b6496c26fdTadashi G. Takaoka        // This will set the punctuation suggestions if next word suggestion is off;
977affdd364232549d2062fc180f924f5b6496c26fdTadashi G. Takaoka        // otherwise it will clear the suggestion strip.
978145e8568f444bf4b102b2da73e0be8a2b04b50a1Jean Chalard        setNeutralSuggestionStrip();
9798e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard
9808e36e5102e9ac294a0e64ca14920d38ba19e6eb3Jean Chalard        mHandler.cancelUpdateSuggestionStrip();
981c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
982adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi        mainKeyboardView.setMainDictionaryAvailability(
9838cd53266229895a3e0c6618e3765d57fc5d0b392Jean Chalard                mDictionaryFacilitator.hasAtLeastOneInitializedMainDictionary());
984b60e65a0cce9f20ee5e633921732785f99fffd2eKen Wakasa        mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn,
985b60e65a0cce9f20ee5e633921732785f99fffd2eKen Wakasa                currentSettingsValues.mKeyPreviewPopupDismissDelay);
986ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka        mainKeyboardView.setSlidingKeyInputPreviewEnabled(
987b60e65a0cce9f20ee5e633921732785f99fffd2eKen Wakasa                currentSettingsValues.mSlidingKeyInputPreviewEnabled);
988ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka        mainKeyboardView.setGestureHandlingEnabledByUser(
989724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa                currentSettingsValues.mGestureInputEnabled,
990724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa                currentSettingsValues.mGestureTrailEnabled,
991b60e65a0cce9f20ee5e633921732785f99fffd2eKen Wakasa                currentSettingsValues.mGestureFloatingPreviewTextEnabled);
992c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
993c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka        if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
994c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka    }
995c1c4ee6b3a8c3ec42edefe42fd183f3cbf67b0bfTadashi G. Takaoka
996923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
9976c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka    public void onWindowShown() {
9986c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka        super.onWindowShown();
9996c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka        setNavigationBarVisibility(isInputViewShown());
10006c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka    }
10016c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka
10026c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka    @Override
1003e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    public void onWindowHidden() {
1004e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        super.onWindowHidden();
1005f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
100627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        if (mainKeyboardView != null) {
100727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka            mainKeyboardView.closing();
100827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        }
10096c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka        setNavigationBarVisibility(false);
1010e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    }
1011e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
10125f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void onFinishInputInternal() {
1013923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onFinishInput();
1014a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
10159bad1ac33f65dc3454a689b88560988b77a00a87Dan Zivkovic        mDictionaryFacilitator.onFinishInput(this);
1016f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
101727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        if (mainKeyboardView != null) {
101827e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka            mainKeyboardView.closing();
101927e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        }
1020466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1021466741d8a78965b8509bf527344f289e50873092Mike LeBeau
10225f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    void onFinishInputViewInternal(final boolean finishingInput) {
10236495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa        super.onFinishInputView(finishingInput);
10249395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        cleanupInternalStateForFinishInput();
10259395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard    }
10269395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard
10279395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard    private void cleanupInternalStateForFinishInput() {
1028d7641636db8fe91d9847ac79f5f431963e876ec3Tadashi G. Takaoka        // Remove pending messages related to update suggestions
1029d81e7d24d384a2bb1aeda65d9b423e4b1d23f185Jean Chalard        mHandler.cancelUpdateSuggestionStrip();
1030ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        // Should do the following in onFinishInputInternal but until JB MR2 it's not called :(
103181e0ca5fd395fd67c7b93e7d87e7d90fa136f065Jean Chalard        mInputLogic.finishInput();
10326495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    }
10336495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa
10347b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu    protected void deallocateMemory() {
10357b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu        mKeyboardSwitcher.deallocateMemory();
10367b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu    }
10377b8f3170504ab3f1b4f8eda02ed6f8fb43bdd5cfAdrian Velicu
10386495bfc7a6f6bfa6ab82e7f062ee80f4b6b33368Ken Wakasa    @Override
1039f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onUpdateSelection(final int oldSelStart, final int oldSelEnd,
1040f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka            final int newSelStart, final int newSelEnd,
1041f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka            final int composingSpanStart, final int composingSpanEnd) {
1042923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
1043104453908064dcdbb4f10aa4150f1d79beafb408Jean Chalard                composingSpanStart, composingSpanEnd);
1044edaa83bb32e7299b5bba2c42d703701c1e2a3d5bDan Zivkovic        if (DebugFlags.DEBUG_ENABLED) {
104512ff7da19df29511e489f426f372300a674f756aKen Wakasa            Log.i(TAG, "onUpdateSelection: oss=" + oldSelStart + ", ose=" + oldSelEnd
104612ff7da19df29511e489f426f372300a674f756aKen Wakasa                    + ", nss=" + newSelStart + ", nse=" + newSelEnd
104712ff7da19df29511e489f426f372300a674f756aKen Wakasa                    + ", cs=" + composingSpanStart + ", ce=" + composingSpanEnd);
1048466741d8a78965b8509bf527344f289e50873092Mike LeBeau        }
1049466741d8a78965b8509bf527344f289e50873092Mike LeBeau
1050ab68143ad0fb784db38a3fd65612632fca90c789Jean Chalard        // This call happens whether our view is displayed or not, but if it's not then we should
1051ab68143ad0fb784db38a3fd65612632fca90c789Jean Chalard        // not attempt recorrection. This is true even with a hardware keyboard connected: if the
1052ab68143ad0fb784db38a3fd65612632fca90c789Jean Chalard        // view is not displayed we have no means of showing suggestions anyway, and if it is then
1053ab68143ad0fb784db38a3fd65612632fca90c789Jean Chalard        // we want to show suggestions anyway.
10549395014e76877fc9ef060a3fe54a9e06f0036d6dJean Chalard        final SettingsValues settingsValues = mSettings.getCurrent();
1055ab68143ad0fb784db38a3fd65612632fca90c789Jean Chalard        if (isInputViewShown()
1056ecea8551c39a497e036be5c010d7ddb6b51a36bcJean Chalard                && mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
1057ecea8551c39a497e036be5c010d7ddb6b51a36bcJean Chalard                        settingsValues)) {
10588ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard            mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(),
10598ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard                    getCurrentRecapitalizeState());
10604733609947c0ec74e460bd714fffca0518ade93aJean Chalard        }
10617a8dac55278cedd838be325f56b4c52d973c61f5satok    }
10627a8dac55278cedd838be325f56b4c52d973c61f5satok
1063c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
1064c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has clicked on the extracted text view,
1065c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * when running in fullscreen mode.  The default implementation hides
1066913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * the suggestions view when this happens, but only if the extracted text
1067c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * editor has a vertical scroll bar because its text doesn't fit.
1068c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
1069913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * cause the suggestions strip to disappear and re-appear.
1070c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
1071c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
1072c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    public void onExtractedTextClicked() {
1073ab661e3ef886a36b02fe094864ae4be6a3260f71Tadashi G. Takaoka        if (mSettings.getCurrent().needsToLookupSuggestions()) {
1074aa161eb371d8042ef4c1f9207648b3aeacb65e4eJean Chalard            return;
1075aa161eb371d8042ef4c1f9207648b3aeacb65e4eJean Chalard        }
1076c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
1077c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedTextClicked();
1078c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
1079c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
1080c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    /**
1081c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * This is called when the user has performed a cursor movement in the
1082c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * extracted text view, when it is running in fullscreen mode.  The default
1083913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * implementation hides the suggestions view when a vertical movement
1084c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * happens, but only if the extracted text editor has a vertical scroll bar
1085c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * because its text doesn't fit.
1086c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     * Here we override the behavior due to the possibility that a re-correction could
1087913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * cause the suggestions strip to disappear and re-appear.
1088c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani     */
1089c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    @Override
1090f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onExtractedCursorMovement(final int dx, final int dy) {
1091ab661e3ef886a36b02fe094864ae4be6a3260f71Tadashi G. Takaoka        if (mSettings.getCurrent().needsToLookupSuggestions()) {
1092aa161eb371d8042ef4c1f9207648b3aeacb65e4eJean Chalard            return;
1093aa161eb371d8042ef4c1f9207648b3aeacb65e4eJean Chalard        }
1094c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
1095c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani        super.onExtractedCursorMovement(dx, dy);
1096c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani    }
1097c1020c3aa65b1eef4c672564750c020d012c4ec2Amith Yamasani
1098923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
1099923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void hideWindow() {
1100c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka        mKeyboardSwitcher.onHideWindow();
1101979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (TRACE) Debug.stopMethodTracing();
110330d5ed67d6548a4d7efa6354d41ac9719a4e4488Tadashi G. Takaoka        if (isShowingOptionDialog()) {
11046e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog.dismiss();
11056e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani            mOptionsDialog = null;
11066e3d427c320e89c6155cbcf4045e399b9b55f48fAmith Yamasani        }
1107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.hideWindow();
1108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
1111f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onDisplayCompletions(final CompletionInfo[] applicationSpecifiedCompletions) {
1112edaa83bb32e7299b5bba2c42d703701c1e2a3d5bDan Zivkovic        if (DebugFlags.DEBUG_ENABLED) {
1113a776b7fc4a0d2c7f05eaed107e9d5db3b575b9d0Ken Wakasa            Log.i(TAG, "Received completions:");
1114bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok            if (applicationSpecifiedCompletions != null) {
1115bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
1116bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                    Log.i(TAG, "  #" + i + ": " + applicationSpecifiedCompletions[i]);
1117bcfce3b3b9dbd4f5db736948b74bd820fc639a08satok                }
1118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
1119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
11202312c1954f86b5fd3b8e5099da814ad73e5a5e26Ken Wakasa        if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) {
11212312c1954f86b5fd3b8e5099da814ad73e5a5e26Ken Wakasa            return;
11222312c1954f86b5fd3b8e5099da814ad73e5a5e26Ken Wakasa        }
1123e2744c6384b49b9e90837be92e78613224ea8a33Jean Chalard        // If we have an update request in flight, we need to cancel it so it does not override
1124e2744c6384b49b9e90837be92e78613224ea8a33Jean Chalard        // these completions.
1125e2744c6384b49b9e90837be92e78613224ea8a33Jean Chalard        mHandler.cancelUpdateSuggestionStrip();
1126dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard        if (applicationSpecifiedCompletions == null) {
112707eddf3c43859008892c78aa282f203591b4cffcJean Chalard            setNeutralSuggestionStrip();
1128dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard            return;
1129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1130dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard
1131dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard        final ArrayList<SuggestedWords.SuggestedWordInfo> applicationSuggestedWords =
1132dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard                SuggestedWords.getFromApplicationSpecifiedCompletions(
1133dca729fddd69f03d8eaca238c62478a7fd77db96Jean Chalard                        applicationSpecifiedCompletions);
11342312c1954f86b5fd3b8e5099da814ad73e5a5e26Ken Wakasa        final SuggestedWords suggestedWords = new SuggestedWords(applicationSuggestedWords,
113583f9524b8796d94fad56280f6b26c9045fea313fJean Chalard                null /* rawSuggestions */,
113683f9524b8796d94fad56280f6b26c9045fea313fJean Chalard                null /* typedWord */,
113783f9524b8796d94fad56280f6b26c9045fea313fJean Chalard                false /* typedWordValid */,
113883f9524b8796d94fad56280f6b26c9045fea313fJean Chalard                false /* willAutoCorrect */,
11398380f921f7edaeea2033a1e967a14941400fe246Jean Chalard                false /* isObsoleteSuggestions */,
114083f9524b8796d94fad56280f6b26c9045fea313fJean Chalard                SuggestedWords.INPUT_STYLE_APPLICATION_SPECIFIED /* inputStyle */,
114183f9524b8796d94fad56280f6b26c9045fea313fJean Chalard                SuggestedWords.NOT_A_SEQUENCE_NUMBER);
11422312c1954f86b5fd3b8e5099da814ad73e5a5e26Ken Wakasa        // When in fullscreen mode, show completions generated by the application forcibly
1143987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        setSuggestedWords(suggestedWords);
1144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1146543dbdfdbda259aa56be9670480c7d802beba332Ken Wakasa    @Override
1147f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onComputeInsets(final InputMethodService.Insets outInsets) {
1148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.onComputeInsets(outInsets);
114996d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        // This method may be called before {@link #setInputView(View)}.
115096d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        if (mInputView == null) {
115196d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka            return;
115296d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        }
11536bb6d30344259b41387f15f0e05df2388beb1d1cJean Chalard        final SettingsValues settingsValues = mSettings.getCurrent();
115456e1b7e4f112a268371c84606e6f4239aef91333Ken Wakasa        final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
115512ff7da19df29511e489f426f372300a674f756aKen Wakasa        if (visibleKeyboardView == null || !hasSuggestionStripView()) {
115646ca84584810dfe606e709b3fe283cbde8aba5f5Tadashi G. Takaoka            return;
115727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        }
115837beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        final int inputHeight = mInputView.getHeight();
11591fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        if (isImeSuppressedByHardwareKeyboard() && !visibleKeyboardView.isShown()) {
11608fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka            // If there is a hardware keyboard and a visible software keyboard view has been hidden,
11618fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka            // no visual element will be shown on the screen.
116298dfa6e3346b95f3da8869048715e2e18f85d65eTadashi G. Takaoka            outInsets.contentTopInsets = inputHeight;
116337beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            outInsets.visibleTopInsets = inputHeight;
116415480481be790c913b0117d0841565efd399cd01Tadashi G. Takaoka            mInsetsUpdater.setInsets(outInsets);
11658fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka            return;
11668fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka        }
116737beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        final int suggestionsHeight = (!mKeyboardSwitcher.isShowingEmojiPalettes()
116837beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka                && mSuggestionStripView.getVisibility() == View.VISIBLE)
116937beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka                ? mSuggestionStripView.getHeight() : 0;
1170be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka        final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - suggestionsHeight;
117137beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        mSuggestionStripView.setMoreSuggestionsHeight(visibleTopY);
117298dfa6e3346b95f3da8869048715e2e18f85d65eTadashi G. Takaoka        // Need to set expanded touchable region only if a keyboard view is being shown.
117356e1b7e4f112a268371c84606e6f4239aef91333Ken Wakasa        if (visibleKeyboardView.isShown()) {
117437beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            final int touchLeft = 0;
117537beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            final int touchTop = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
1176be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka            final int touchRight = visibleKeyboardView.getWidth();
117737beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            final int touchBottom = inputHeight
11787a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    // Extend touchable region below the keyboard.
11797a3d3ae17f7a8ca0b44e9c92328a7de7cbc80f92Tadashi G. Takaoka                    + EXTENDED_TOUCHABLE_REGION_HEIGHT;
118013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka            outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
118137beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            outInsets.touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom);
11829e347d3d448e48229c46aad394ec9bd60cd5807bsatok        }
1183c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa        outInsets.contentTopInsets = visibleTopY;
1184c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa        outInsets.visibleTopInsets = visibleTopY;
118515480481be790c913b0117d0841565efd399cd01Tadashi G. Takaoka        mInsetsUpdater.setInsets(outInsets);
1186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1187a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
118896d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka    public void startShowingInputView(final boolean needsToLoadKeyboard) {
118988f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        mIsExecutingStartShowingInputView = true;
119088f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        // This {@link #showWindow(boolean)} will eventually call back
119188f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        // {@link #onEvaluateInputViewShown()}.
119288f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        showWindow(true /* showInput */);
119388f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        mIsExecutingStartShowingInputView = false;
119496d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        if (needsToLoadKeyboard) {
119596d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka            loadKeyboard();
119696d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        }
119788f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka    }
119888f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka
119988f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka    public void stopShowingInputView() {
120088f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        showWindow(false /* showInput */);
12018fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka    }
12028fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka
12038fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka    @Override
120496d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka    public boolean onShowInputRequested(final int flags, final boolean configChange) {
12051fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        if (isImeSuppressedByHardwareKeyboard()) {
120696d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka            return true;
120796d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        }
120896d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        return super.onShowInputRequested(flags, configChange);
120996d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka    }
121096d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka
121196d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka    @Override
121288f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka    public boolean onEvaluateInputViewShown() {
121388f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        if (mIsExecutingStartShowingInputView) {
121419dd34a02320b7a368c4ad65398248ceca41b69eTadashi G. Takaoka            return true;
121519dd34a02320b7a368c4ad65398248ceca41b69eTadashi G. Takaoka        }
121688f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        return super.onEvaluateInputViewShown();
121719dd34a02320b7a368c4ad65398248ceca41b69eTadashi G. Takaoka    }
121819dd34a02320b7a368c4ad65398248ceca41b69eTadashi G. Takaoka
121919dd34a02320b7a368c4ad65398248ceca41b69eTadashi G. Takaoka    @Override
1220979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public boolean onEvaluateFullscreenMode() {
12216bb6d30344259b41387f15f0e05df2388beb1d1cJean Chalard        final SettingsValues settingsValues = mSettings.getCurrent();
12221fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        if (isImeSuppressedByHardwareKeyboard()) {
12238fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka            // If there is a hardware keyboard, disable full screen mode.
12248fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka            return false;
12258fdff5a11129827e88ce9f5bc462e18f613c19a3Tadashi G. Takaoka        }
122630a72da42c479adb4cedff5d7a40846a3103ac9bJean Chalard        // Reread resource value here, because this method is called by the framework as needed.
12272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources());
122860dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka        if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) {
122960dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka            // TODO: Remove this hack. Actually we should not really assume NO_EXTRACT_UI
123060dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka            // implies NO_FULLSCREEN. However, the framework mistakenly does.  i.e. NO_EXTRACT_UI
123160dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka            // without NO_FULLSCREEN doesn't work as expected. Because of this we need this
123260dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka            // hack for now.  Let's get rid of this once the framework gets fixed.
123360dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka            final EditorInfo ei = getCurrentInputEditorInfo();
123460dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka            return !(ei != null && ((ei.imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0));
123560dea36dafc4a567b948b5175bcca776b08fdfadSatoshi Kataoka        }
123688f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        return false;
123759010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka    }
123859010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka
123959010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka    @Override
124059010a89b839ea181dc07588df21f3db29ee8bd1Tadashi G. Takaoka    public void updateFullscreenMode() {
124196d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        super.updateFullscreenMode();
124296d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        updateSoftInputWindowLayoutParameters();
124396d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka    }
124496d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka
124596d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka    private void updateSoftInputWindowLayoutParameters() {
124637beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        // Override layout parameters to expand {@link SoftInputWindow} to the entire screen.
124796d31df8c452a2a6230a5e8c03b0cab1ab13ff80Tadashi G. Takaoka        // See {@link InputMethodService#setinputView(View)} and
124837beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        // {@link SoftInputWindow#updateWidthHeight(WindowManager.LayoutParams)}.
124937beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        final Window window = getWindow().getWindow();
125037beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        ViewLayoutUtils.updateLayoutHeightOf(window, LayoutParams.MATCH_PARENT);
125137beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        // This method may be called before {@link #setInputView(View)}.
125237beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        if (mInputView != null) {
125337beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            // In non-fullscreen mode, {@link InputView} and its parent inputArea should expand to
125437beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            // the entire screen and be placed at the bottom of {@link SoftInputWindow}.
125537beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            // In fullscreen mode, these shouldn't expand to the entire screen and should be
125637beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            // coexistent with {@link #mExtractedArea} above.
125737beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            // See {@link InputMethodService#setInputView(View) and
125837beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            // com.android.internal.R.layout.input_method.xml.
125937beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            final int layoutHeight = isFullscreenMode()
126037beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka                    ? LayoutParams.WRAP_CONTENT : LayoutParams.MATCH_PARENT;
126137beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            final View inputArea = window.findViewById(android.R.id.inputArea);
126237beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            ViewLayoutUtils.updateLayoutHeightOf(inputArea, layoutHeight);
126337beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            ViewLayoutUtils.updateLayoutGravityOf(inputArea, Gravity.BOTTOM);
126437beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka            ViewLayoutUtils.updateLayoutHeightOf(mInputView, layoutHeight);
126537beaf1529a61228d6240736937789e5622b29edTadashi G. Takaoka        }
1266979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
1267979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
12685f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    int getCurrentAutoCapsState() {
126910460441db805e78c3384cdba4fe011996221534Jean Chalard        return mInputLogic.getCurrentAutoCapsState(mSettings.getCurrent());
12701c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
12711c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
12725f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka    int getCurrentRecapitalizeState() {
127348ba1f25ffb40780fb97093ee9a8ce118a801740Jean Chalard        return mInputLogic.getCurrentRecapitalizeState();
12748094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard    }
12758094bf45d73a5f7257076afc97d91d6708ee03c4Jean Chalard
1276d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard    /**
1277d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard     * @param codePoints code points to get coordinates for.
1278d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard     * @return x,y coordinates for this keyboard, as a flattened array.
1279d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard     */
1280d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard    public int[] getCoordinatesForCurrentKeyboard(final int[] codePoints) {
12811d6e647ac31eab38f30b8ed468551d1e3a07c705Jean Chalard        final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
12821d6e647ac31eab38f30b8ed468551d1e3a07c705Jean Chalard        if (null == keyboard) {
12831d6e647ac31eab38f30b8ed468551d1e3a07c705Jean Chalard            return CoordinateUtils.newCoordinateArray(codePoints.length,
12841d6e647ac31eab38f30b8ed468551d1e3a07c705Jean Chalard                    Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
1285d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard        }
128688f282de0dbb92c7d423c30a84395893d6765092Tadashi G. Takaoka        return keyboard.getCoordinates(codePoints);
1287d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard    }
1288d1f463eacfaac31a999f7eb1ecaa1668ed3038d4Jean Chalard
12898a296e43c903a3377f28943ba4a59082ae7fe60aTadashi G. Takaoka    // Callback for the {@link SuggestionStripView}, to call when the important notice strip is
12908a296e43c903a3377f28943ba4a59082ae7fe60aTadashi G. Takaoka    // pressed.
12918a296e43c903a3377f28943ba4a59082ae7fe60aTadashi G. Takaoka    @Override
12928a296e43c903a3377f28943ba4a59082ae7fe60aTadashi G. Takaoka    public void showImportantNoticeContents() {
1293604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheik        PermissionsManager.get(this).requestPermissions(
1294604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheik                this /* PermissionsResultCallback */,
1295604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheik                null /* activity */, permission.READ_CONTACTS);
1296d73044a2494873a4abe0d4da208533164314d2f0Tadashi G. Takaoka    }
1297d73044a2494873a4abe0d4da208533164314d2f0Tadashi G. Takaoka
1298d73044a2494873a4abe0d4da208533164314d2f0Tadashi G. Takaoka    @Override
1299604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheik    public void onRequestPermissionsResult(boolean allGranted) {
1300604158669b407a40cd0f23538fad4dce5d738f24Mohammadinamul Sheik        ImportantNoticeUtils.updateContactsNoticeShown(this /* context */);
1301d73044a2494873a4abe0d4da208533164314d2f0Tadashi G. Takaoka        setNeutralSuggestionStrip();
13026abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka    }
13036abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka
13045c9e677c2abc6529c19fcc858ef987756d4341efJean Chalard    public void displaySettingsDialog() {
130512ff7da19df29511e489f426f372300a674f756aKen Wakasa        if (isShowingOptionDialog()) {
130612ff7da19df29511e489f426f372300a674f756aKen Wakasa            return;
130712ff7da19df29511e489f426f372300a674f756aKen Wakasa        }
1308911b8f9d19c1c4903eeef29b43176cfeaa0e5d0cKen Wakasa        showSubtypeSelectorAndSettings();
13099a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
13109a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1311cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa    @Override
1312f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public boolean onCustomRequest(final int requestCode) {
1313cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        if (isShowingOptionDialog()) return false;
1314cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        switch (requestCode) {
1315f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka        case Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER:
13166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
13176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                mRichImm.getInputMethodManager().showInputMethodPicker();
1318cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa                return true;
13199a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok            }
1320cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa            return false;
13219a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        }
1322cadb2128f54b49be31bb4dc06374afe81ed028b7Ken Wakasa        return false;
13239a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
13249a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
13259a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    private boolean isShowingOptionDialog() {
13269a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok        return mOptionsDialog != null && mOptionsDialog.isShowing();
13279a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok    }
13289a6a4d3d5f1ee52b56d349c002aa61c264d010d3satok
1329809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa    public void switchLanguage(final InputMethodSubtype subtype) {
1330809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        final IBinder token = getWindow().getWindow().getAttributes().token;
1331809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa        mRichImm.setInputMethodAndSubtype(token, subtype);
1332809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa    }
1333809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa
1334aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka    // TODO: Revise the language switch key behavior to make it much smarter and more reasonable.
133548ba1f25ffb40780fb97093ee9a8ce118a801740Jean Chalard    public void switchToNextSubtype() {
133681d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka        final IBinder token = getWindow().getWindow().getAttributes().token;
13378ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        if (shouldSwitchToOtherInputMethods()) {
13386fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            mRichImm.switchToNextInputMethod(token, false /* onlyCurrentIme */);
1339aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka            return;
1340aec5cc84760b47661ccc5a0c938368d3798be6b4Tadashi G. Takaoka        }
13411931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        mSubtypeState.switchSubtype(token, mRichImm);
134281d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka    }
134381d4e3cd66a9388c47c7dba55240ddf849b31934Tadashi G. Takaoka
1344908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
1345908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    // alphabetic shift and shift while in symbol layout and get rid of this method.
1346908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    private int getCodePointForKeyboard(final int codePoint) {
1347908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard        if (Constants.CODE_SHIFT == codePoint) {
1348908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard            final Keyboard currentKeyboard = mKeyboardSwitcher.getKeyboard();
1349908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard            if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
1350908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard                return codePoint;
1351908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard            }
13525f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            return Constants.CODE_SYMBOL_SHIFT;
1353908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard        }
13545f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        return codePoint;
1355908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    }
1356908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard
13575f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    // Implementation of {@link KeyboardActionListener}.
13585a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
13592282e8520a2c1984989a14fb09896536f5033b26Jean Chalard    public void onCodeInput(final int codePoint, final int x, final int y,
13602282e8520a2c1984989a14fb09896536f5033b26Jean Chalard            final boolean isKeyRepeat) {
1361908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard        // TODO: this processing does not belong inside LatinIME, the caller should be doing this.
1362352286a43b0f951a5082ca741c2bd7f501f48c81Jean Chalard        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
1363352286a43b0f951a5082ca741c2bd7f501f48c81Jean Chalard        // x and y include some padding, but everything down the line (especially native
1364352286a43b0f951a5082ca741c2bd7f501f48c81Jean Chalard        // code) needs the coordinates in the keyboard frame.
1365352286a43b0f951a5082ca741c2bd7f501f48c81Jean Chalard        // TODO: We should reconsider which coordinate system should be used to represent
1366352286a43b0f951a5082ca741c2bd7f501f48c81Jean Chalard        // keyboard event. Also we should pull this up -- LatinIME has no business doing
1367e38043849e01adfb2f6eb33cf6133c1d39d2466aJean Chalard        // this transformation, it should be done already before calling onEvent.
1368a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard        final int keyX = mainKeyboardView.getKeyX(x);
1369a91dfff5e54f68c4003327eeca47286084c35a2fJean Chalard        final int keyY = mainKeyboardView.getKeyY(y);
1370908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard        final Event event = createSoftwareKeypressEvent(getCodePointForKeyboard(codePoint),
1371908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard                keyX, keyY, isKeyRepeat);
1372908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard        onEvent(event);
1373908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    }
1374908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard
1375908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    // This method is public for testability of LatinIME, but also in the future it should
1376908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    // completely replace #onCodeInput.
1377d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka    public void onEvent(@Nonnull final Event event) {
1378e38043849e01adfb2f6eb33cf6133c1d39d2466aJean Chalard        if (Constants.CODE_SHORTCUT == event.mKeyCode) {
13794486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka            mRichImm.switchToShortcutIme(this);
1380969c06072db7f530806a4d0581ce588f01d09dc2Jean Chalard        }
1381a1bf550294dfb5e6e7e5eba78a8db491c5bab2d4Jean Chalard        final InputTransaction completeInputTransaction =
1382a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard                mInputLogic.onCodeInput(mSettings.getCurrent(), event,
138335c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                        mKeyboardSwitcher.getKeyboardShiftMode(),
138435c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                        mKeyboardSwitcher.getCurrentKeyboardScriptId(), mHandler);
13856bd3723e733308a8b6d88830335bb5f786235369Jean Chalard        updateStateAfterInputTransaction(completeInputTransaction);
1386e38043849e01adfb2f6eb33cf6133c1d39d2466aJean Chalard        mKeyboardSwitcher.onEvent(event, getCurrentAutoCapsState(), getCurrentRecapitalizeState());
1387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1388a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1389a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard    // A helper method to split the code point and the key code. Ultimately, they should not be
1390a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard    // squashed into the same variable, and this method should be removed.
1391908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    // public for testing, as we don't want to copy the same logic into test code
1392d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka    @Nonnull
1393908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard    public static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX,
13942282e8520a2c1984989a14fb09896536f5033b26Jean Chalard             final int keyY, final boolean isKeyRepeat) {
1395a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard        final int keyCode;
1396a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard        final int codePoint;
1397a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard        if (keyCodeOrCodePoint <= 0) {
1398a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard            keyCode = keyCodeOrCodePoint;
1399a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard            codePoint = Event.NOT_A_CODE_POINT;
1400a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard        } else {
1401a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard            keyCode = Event.NOT_A_KEY_CODE;
1402a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard            codePoint = keyCodeOrCodePoint;
1403a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard        }
14042282e8520a2c1984989a14fb09896536f5033b26Jean Chalard        return Event.createSoftwareKeypressEvent(codePoint, keyCode, keyX, keyY, isKeyRepeat);
1405a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard    }
1406a79a3265db6482a0bcaf0dfa87036a9243af281dJean Chalard
1407e193c5255d96d3971ee207b459a8a1e91c0d176cYuichiro Hanada    // Called from PointerTracker through the KeyboardActionListener interface
1408e193c5255d96d3971ee207b459a8a1e91c0d176cYuichiro Hanada    @Override
1409e193c5255d96d3971ee207b459a8a1e91c0d176cYuichiro Hanada    public void onTextInput(final String rawText) {
1410058a38988b607e1364e6491b97960d2044ad5068Jean Chalard        // TODO: have the keyboard pass the correct key code when we need it.
1411e38043849e01adfb2f6eb33cf6133c1d39d2466aJean Chalard        final Event event = Event.createSoftwareTextEvent(rawText, Constants.CODE_OUTPUT_TEXT);
14126345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard        final InputTransaction completeInputTransaction =
14136345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard                mInputLogic.onTextInput(mSettings.getCurrent(), event,
14146345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard                        mKeyboardSwitcher.getKeyboardShiftMode(), mHandler);
14156345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard        updateStateAfterInputTransaction(completeInputTransaction);
1416e38043849e01adfb2f6eb33cf6133c1d39d2466aJean Chalard        mKeyboardSwitcher.onEvent(event, getCurrentAutoCapsState(), getCurrentRecapitalizeState());
1417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
14194be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka    @Override
14204be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka    public void onStartBatchInput() {
14212ca916c215e46d192391e2963037072bafff8ce3Jean Chalard        mInputLogic.onStartBatchInput(mSettings.getCurrent(), mKeyboardSwitcher, mHandler);
1422c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer.onGestureStarted(
1423107fb4c476779df16be23e245547253978c197acDan Zivkovic                mRichImm.getCurrentSubtypeLocale(),
1424c92c883fdf2287b49392692fa2e8d109dc26f785David Faden                mKeyboardSwitcher.getKeyboard());
14251587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    }
14261587be697752b12e18d5cadb90e56883cb93c242Jean Chalard
14271587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    @Override
14281587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    public void onUpdateBatchInput(final InputPointers batchPointers) {
1429fe716f0f73ee551ce42b523983f92efccce79dc8Dan Zivkovic        mInputLogic.onUpdateBatchInput(batchPointers);
14301587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    }
14311587be697752b12e18d5cadb90e56883cb93c242Jean Chalard
14321587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    @Override
14331587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    public void onEndBatchInput(final InputPointers batchPointers) {
1434151761a2764c09c0e5bc48c68e0c804aeaf22d11Jean Chalard        mInputLogic.onEndBatchInput(batchPointers);
1435c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer.onGestureCompleted(batchPointers);
14361587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    }
14371587be697752b12e18d5cadb90e56883cb93c242Jean Chalard
14381587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    @Override
14391587be697752b12e18d5cadb90e56883cb93c242Jean Chalard    public void onCancelBatchInput() {
144053c320e2757ec37e40dc1dc54a2b04a05a995003Jean Chalard        mInputLogic.onCancelBatchInput(mHandler);
1441c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer.onGestureCanceled();
1442c92c883fdf2287b49392692fa2e8d109dc26f785David Faden    }
1443c92c883fdf2287b49392692fa2e8d109dc26f785David Faden
1444c92c883fdf2287b49392692fa2e8d109dc26f785David Faden    /**
1445f296e7cdfa3af2f666c182f04ea5c3f10945de40Ken Wakasa     * To be called after the InputLogic has gotten a chance to act on the suggested words by the
1446f296e7cdfa3af2f666c182f04ea5c3f10945de40Ken Wakasa     * IME for the full gesture, possibly updating the TextView to reflect the first suggestion.
1447c92c883fdf2287b49392692fa2e8d109dc26f785David Faden     * <p>
1448c92c883fdf2287b49392692fa2e8d109dc26f785David Faden     * This method must be run on the UI Thread.
1449f296e7cdfa3af2f666c182f04ea5c3f10945de40Ken Wakasa     * @param suggestedWords suggested words by the IME for the full gesture.
1450c92c883fdf2287b49392692fa2e8d109dc26f785David Faden     */
1451c92c883fdf2287b49392692fa2e8d109dc26f785David Faden    public void onTailBatchInputResultShown(final SuggestedWords suggestedWords) {
1452c92c883fdf2287b49392692fa2e8d109dc26f785David Faden        mGestureConsumer.onImeSuggestionsProcessed(suggestedWords,
14536e86632311a24af90ad35c98224ae25f226c1954David Faden                mInputLogic.getComposingStart(), mInputLogic.getComposingLength(),
14546e86632311a24af90ad35c98224ae25f226c1954David Faden                mDictionaryFacilitator);
1455f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    }
1456f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka
145752a2682b99fc57dea974b21f3d606ed53a802e60Jean Chalard    // This method must run on the UI Thread.
14582ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka    void showGesturePreviewAndSuggestionStrip(@Nonnull final SuggestedWords suggestedWords,
1459f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka            final boolean dismissGestureFloatingPreviewText) {
1460fa7075768da25341bf84e9f87bba09356961e2e8Jean Chalard        showSuggestionStrip(suggestedWords);
1461375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
14622ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka        mainKeyboardView.showGestureFloatingPreviewText(suggestedWords,
14632ad6d9cda33825fa265cd17372f115bb48f49d19Tadashi G. Takaoka                dismissGestureFloatingPreviewText /* dismissDelayed */);
14644be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka    }
14654be03befe3cf771a33448367f50c517dc01ced21Tadashi G. Takaoka
1466a5bb353de92a6a6d010ba1695b9dd22b3a617b77Jean Chalard    // Called from PointerTracker through the KeyboardActionListener interface
14675a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
146841016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka    public void onFinishSlidingInput() {
146941016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka        // User finished sliding input.
1470f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard        mKeyboardSwitcher.onFinishSlidingInput(getCurrentAutoCapsState(),
1471f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard                getCurrentRecapitalizeState());
147241016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka    }
147341016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka
147441016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka    // Called from PointerTracker through the KeyboardActionListener interface
147541016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka    @Override
14768aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka    public void onCancelInput() {
147783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka        // User released a finger outside any key
147841016acacfa21354f59ed51db1f85ea3d99bf6a4Tadashi G. Takaoka        // Nothing to do so far.
147983e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka    }
148083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka
1481ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard    public boolean hasSuggestionStripView() {
1482ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard        return null != mSuggestionStripView;
1483ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard    }
1484ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard
1485987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka    private void setSuggestedWords(final SuggestedWords suggestedWords) {
1486bea17c49ec23bf0f646cb548445c7756aa50d233Yohei Yukawa        final SettingsValues currentSettingsValues = mSettings.getCurrent();
1487176ad53c6fee47df7595e7501e7e2829d990364dJean Chalard        mInputLogic.setSuggestedWords(suggestedWords);
1488129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard        // TODO: Modify this when we support suggestions with hard keyboard
148912ff7da19df29511e489f426f372300a674f756aKen Wakasa        if (!hasSuggestionStripView()) {
1490affdd364232549d2062fc180f924f5b6496c26fdTadashi G. Takaoka            return;
1491675f1dbaf0c9a2e01fe04c07ceb23f6b79721fd0Jean Chalard        }
1492129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard        if (!onEvaluateInputViewShown()) {
1493129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard            return;
1494129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard        }
1495aa4b2c71270576f25e7c80a4b63a1956cec5f4e2Tadashi G. Takaoka
1496987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        final boolean shouldShowImportantNotice =
14978ec36026c93d13c1118eda936ac12325e0085561Chieu Nguyen                ImportantNoticeUtils.shouldShowImportantNotice(this, currentSettingsValues);
14986a96c508fddde10827b8f0822a7096bf4b708cf0Tadashi G. Takaoka        final boolean shouldShowSuggestionCandidates =
14996a96c508fddde10827b8f0822a7096bf4b708cf0Tadashi G. Takaoka                currentSettingsValues.mInputAttributes.mShouldShowSuggestions
1500ab661e3ef886a36b02fe094864ae4be6a3260f71Tadashi G. Takaoka                && currentSettingsValues.isSuggestionsEnabledPerUserSettings();
1501987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        final boolean shouldShowSuggestionsStripUnlessPassword = shouldShowImportantNotice
1502987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka                || currentSettingsValues.mShowsVoiceInputKey
15036a96c508fddde10827b8f0822a7096bf4b708cf0Tadashi G. Takaoka                || shouldShowSuggestionCandidates
1504987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka                || currentSettingsValues.isApplicationSpecifiedCompletionsOn();
1505987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        final boolean shouldShowSuggestionsStrip = shouldShowSuggestionsStripUnlessPassword
1506987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka                && !currentSettingsValues.mInputAttributes.mIsPasswordField;
1507987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        mSuggestionStripView.updateVisibility(shouldShowSuggestionsStrip, isFullscreenMode());
1508987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        if (!shouldShowSuggestionsStrip) {
1509129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard            return;
1510129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard        }
1511129ca9e7ebc9316a43ae716cc6ec44e1e17a35faJean Chalard
1512987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka        final boolean isEmptyApplicationSpecifiedCompletions =
1513987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka                currentSettingsValues.isApplicationSpecifiedCompletionsOn()
1514987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka                && suggestedWords.isEmpty();
151530f4a2a4d750dc8c3132d706d9148daf71fbd168Adrian Velicu        final boolean noSuggestionsFromDictionaries = suggestedWords.isEmpty()
15169df51d10fa6b5b21de564cd93926a88690a98600Tadashi G. Takaoka                || suggestedWords.isPunctuationSuggestions()
1517987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka                || isEmptyApplicationSpecifiedCompletions;
1518f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka        final boolean isBeginningOfSentencePrediction = (suggestedWords.mInputStyle
1519f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka                == SuggestedWords.INPUT_STYLE_BEGINNING_OF_SENTENCE_PREDICTION);
1520f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka        final boolean noSuggestionsToOverrideImportantNotice = noSuggestionsFromDictionaries
1521f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka                || isBeginningOfSentencePrediction;
1522f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka        if (shouldShowImportantNotice && noSuggestionsToOverrideImportantNotice) {
15236a96c508fddde10827b8f0822a7096bf4b708cf0Tadashi G. Takaoka            if (mSuggestionStripView.maybeShowImportantNoticeTitle()) {
15246a96c508fddde10827b8f0822a7096bf4b708cf0Tadashi G. Takaoka                return;
15256a96c508fddde10827b8f0822a7096bf4b708cf0Tadashi G. Takaoka            }
1526affdd364232549d2062fc180f924f5b6496c26fdTadashi G. Takaoka        }
1527987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka
1528ab661e3ef886a36b02fe094864ae4be6a3260f71Tadashi G. Takaoka        if (currentSettingsValues.isSuggestionsEnabledPerUserSettings()
1529f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka                || currentSettingsValues.isApplicationSpecifiedCompletionsOn()
1530f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka                // We should clear the contextual strip if there is no suggestion from dictionaries.
1531f4c7eb478f67874e81cce786bf91ab112da316e1Tadashi G. Takaoka                || noSuggestionsFromDictionaries) {
1532affdd364232549d2062fc180f924f5b6496c26fdTadashi G. Takaoka            mSuggestionStripView.setSuggestions(suggestedWords,
15337fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka                    mRichImm.getCurrentSubtype().isRtlSubtype());
1534affdd364232549d2062fc180f924f5b6496c26fdTadashi G. Takaoka        }
1535466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
1536466741d8a78965b8509bf527344f289e50873092Mike LeBeau
153753c320e2757ec37e40dc1dc54a2b04a05a995003Jean Chalard    // TODO[IL]: Move this out of LatinIME.
1538b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard    public void getSuggestedWords(final int inputStyle, final int sequenceNumber,
15399666a228153bb2269da8983762bdd47e448f2cecYuichiro Hanada            final OnGetSuggestedWordsCallback callback) {
1540d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka        final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
1541adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi        if (keyboard == null) {
154230f4a2a4d750dc8c3132d706d9148daf71fbd168Adrian Velicu            callback.onGetSuggestedWords(SuggestedWords.getEmptyInstance());
15439666a228153bb2269da8983762bdd47e448f2cecYuichiro Hanada            return;
1544d445b56ce14152b30143302899790af255691148Tadashi G. Takaoka        }
1545487e038ff329b6099ff5343fb2d7bdc60a6fd699Mario Tanev        mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard,
1546487e038ff329b6099ff5343fb2d7bdc60a6fd699Mario Tanev                mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback);
1547ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard    }
1548ae7d1530b48e31266dbe8c6c5f33481853092170Jean Chalard
1549ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard    @Override
155030f4a2a4d750dc8c3132d706d9148daf71fbd168Adrian Velicu    public void showSuggestionStrip(final SuggestedWords suggestedWords) {
155130f4a2a4d750dc8c3132d706d9148daf71fbd168Adrian Velicu        if (suggestedWords.isEmpty()) {
15522cbf152986a67ddffa909111718bb8d2dc80e5d7Jean Chalard            setNeutralSuggestionStrip();
15532cbf152986a67ddffa909111718bb8d2dc80e5d7Jean Chalard        } else {
1554987bff9136ec101d06db7903ebb3f505e4ea78d6Tadashi G. Takaoka            setSuggestedWords(suggestedWords);
1555c6367ee64d9e301d8c2e920ada57a5550aafa596Jean Chalard        }
1556c6367ee64d9e301d8c2e920ada57a5550aafa596Jean Chalard        // Cache the auto-correction in accessibility code so we can speak it if the user
1557c6367ee64d9e301d8c2e920ada57a5550aafa596Jean Chalard        // touches a key that will insert it.
1558a94733cbca5bc3544fa73fa1649bbb1dadf31356Jean Chalard        AccessibilityUtils.getInstance().setAutoCorrection(suggestedWords);
1559a469743e331e57e3a03354f95268e4addf93b0e8Yuichiro Hanada    }
1560a469743e331e57e3a03354f95268e4addf93b0e8Yuichiro Hanada
15614702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    // Called from {@link SuggestionStripView} through the {@link SuggestionStripView#Listener}
15624702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    // interface
1563c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    @Override
156435c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard    public void pickSuggestionManually(final SuggestedWordInfo suggestionInfo) {
156546e17983c69650415c6469a80c46154cb4299f9dJean Chalard        final InputTransaction completeInputTransaction = mInputLogic.onPickSuggestionManually(
156635c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                mSettings.getCurrent(), suggestionInfo,
156735c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                mKeyboardSwitcher.getKeyboardShiftMode(),
156835c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                mKeyboardSwitcher.getCurrentKeyboardScriptId(),
156935c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                mHandler);
15706bd3723e733308a8b6d88830335bb5f786235369Jean Chalard        updateStateAfterInputTransaction(completeInputTransaction);
15712bb1c6add961e09c21af92c631f3922f1ab36a91Jean Chalard    }
1572979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1573b2c0388a6961b7df96864ba693a2dd84c1f8a1b0Jean Chalard    // This will show either an empty suggestion strip (if prediction is enabled) or
1574b2c0388a6961b7df96864ba693a2dd84c1f8a1b0Jean Chalard    // punctuation suggestions (if it's disabled).
1575ade1aa55b6be938a44b92f7ca6829c53c6258664Jean Chalard    @Override
1576b2c0388a6961b7df96864ba693a2dd84c1f8a1b0Jean Chalard    public void setNeutralSuggestionStrip() {
15775455179b54eb8230577f518db082796a3055685aDan Zivkovic        final SettingsValues currentSettings = mSettings.getCurrent();
15785455179b54eb8230577f518db082796a3055685aDan Zivkovic        final SuggestedWords neutralSuggestions = currentSettings.mBigramPredictionEnabled
15795455179b54eb8230577f518db082796a3055685aDan Zivkovic                ? SuggestedWords.getEmptyInstance()
15805455179b54eb8230577f518db082796a3055685aDan Zivkovic                : currentSettings.mSpacingAndPunctuations.mSuggestPuncList;
15815455179b54eb8230577f518db082796a3055685aDan Zivkovic        setSuggestedWords(neutralSuggestions);
15826a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    }
15836a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
15849fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka    // Outside LatinIME, only used by the {@link InputTestsBase} test suite.
158515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting
15869fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka    void loadKeyboard() {
1587673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        // Since we are switching languages, the most urgent thing is to let the keyboard graphics
1588673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        // update. LoadKeyboard does that, but we need to wait for buffer flip for it to be on
1589673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        // the screen. Anything we do right now will delay this, so wait until the next frame
1590673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        // before we do the rest, like reopening dictionaries and updating suggestions. So we
1591673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        // post a message.
1592673c727b7a42e2cee2df4415111bfa94a0a2df3bJean Chalard        mHandler.postReopenDictionaries();
15930657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka        loadSettings();
159427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        if (mKeyboardSwitcher.getMainKeyboardView() != null) {
15951e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka            // Reload keyboard because the current language has been changed.
1596f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard            mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent(),
1597f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard                    getCurrentAutoCapsState(), getCurrentRecapitalizeState());
15981e39565bb48d23221145c494d4bf5665b514699dTadashi G. Takaoka        }
159936fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani    }
160036fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
16016bd3723e733308a8b6d88830335bb5f786235369Jean Chalard    /**
16026bd3723e733308a8b6d88830335bb5f786235369Jean Chalard     * After an input transaction has been executed, some state must be updated. This includes
16036bd3723e733308a8b6d88830335bb5f786235369Jean Chalard     * the shift state of the keyboard and suggestions. This method looks at the finished
16046bd3723e733308a8b6d88830335bb5f786235369Jean Chalard     * inputTransaction to find out what is necessary and updates the state accordingly.
16056bd3723e733308a8b6d88830335bb5f786235369Jean Chalard     * @param inputTransaction The transaction that has been executed.
16066bd3723e733308a8b6d88830335bb5f786235369Jean Chalard     */
16076bd3723e733308a8b6d88830335bb5f786235369Jean Chalard    private void updateStateAfterInputTransaction(final InputTransaction inputTransaction) {
16086bd3723e733308a8b6d88830335bb5f786235369Jean Chalard        switch (inputTransaction.getRequiredShiftUpdate()) {
160946e17983c69650415c6469a80c46154cb4299f9dJean Chalard        case InputTransaction.SHIFT_UPDATE_LATER:
161046e17983c69650415c6469a80c46154cb4299f9dJean Chalard            mHandler.postUpdateShiftState();
161146e17983c69650415c6469a80c46154cb4299f9dJean Chalard            break;
161246e17983c69650415c6469a80c46154cb4299f9dJean Chalard        case InputTransaction.SHIFT_UPDATE_NOW:
16138ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard            mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(),
16148ab4ae4377fca97cb9ef05c615c5a59bc4bc3d8cJean Chalard                    getCurrentRecapitalizeState());
161546e17983c69650415c6469a80c46154cb4299f9dJean Chalard            break;
161646e17983c69650415c6469a80c46154cb4299f9dJean Chalard        default: // SHIFT_NO_UPDATE
161746e17983c69650415c6469a80c46154cb4299f9dJean Chalard        }
16186bd3723e733308a8b6d88830335bb5f786235369Jean Chalard        if (inputTransaction.requiresUpdateSuggestions()) {
1619b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            final int inputStyle;
1620b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            if (inputTransaction.mEvent.isSuggestionStripPress()) {
1621b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard                // Suggestion strip press: no input.
1622b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard                inputStyle = SuggestedWords.INPUT_STYLE_NONE;
1623b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            } else if (inputTransaction.mEvent.isGesture()) {
1624b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard                inputStyle = SuggestedWords.INPUT_STYLE_TAIL_BATCH;
1625b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            } else {
1626b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard                inputStyle = SuggestedWords.INPUT_STYLE_TYPING;
1627b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            }
1628b8d764772b174cbd37354ffd0009bda56f223dc4Jean Chalard            mHandler.postUpdateSuggestionStrip(inputStyle);
16296bd3723e733308a8b6d88830335bb5f786235369Jean Chalard        }
16306345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard        if (inputTransaction.didAffectContents()) {
16316345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard            mSubtypeState.setCurrentSubtypeHasBeenUsed();
16326345562e2b351221a9bc0341f7dbd26095290b64Jean Chalard        }
163346e17983c69650415c6469a80c46154cb4299f9dJean Chalard    }
163446e17983c69650415c6469a80c46154cb4299f9dJean Chalard
1635ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    private void hapticAndAudioFeedback(final int code, final int repeatCount) {
16366455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka        final MainKeyboardView keyboardView = mKeyboardSwitcher.getMainKeyboardView();
16372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        if (keyboardView != null && keyboardView.isInDraggingFinger()) {
16382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa            // No need to feedback while finger is dragging.
16396455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka            return;
16406455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka        }
1641ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        if (repeatCount > 0) {
16427bd2a75ca180cb5da8ba75500163aa06f332caacJean Chalard            if (code == Constants.CODE_DELETE && !mInputLogic.mConnection.canDeleteCharacters()) {
1643ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka                // No need to feedback when repeat delete key will have no effect.
1644ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka                return;
1645ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            }
1646ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            // TODO: Use event time that the last feedback has been generated instead of relying on
1647ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            // a repeat count to thin out feedback.
1648ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            if (repeatCount % PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT == 0) {
1649ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka                return;
1650ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            }
1651ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        }
1652ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        final AudioAndHapticFeedbackManager feedbackManager =
1653ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka                AudioAndHapticFeedbackManager.getInstance();
1654ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        if (repeatCount == 0) {
1655ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            // TODO: Reconsider how to perform haptic feedback when repeating key.
1656ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka            feedbackManager.performHapticFeedback(keyboardView);
16576455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka        }
1658ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        feedbackManager.performAudioFeedback(code);
16596455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka    }
16606455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka
1661f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka    // Callback of the {@link KeyboardActionListener}. This is called when a key is depressed;
1662f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka    // release matching call is {@link #onReleaseKey(int,boolean)} below.
16635a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1664ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    public void onPressKey(final int primaryCode, final int repeatCount,
16656455172a707a1137eb15db8073774982db9dd1faTadashi G. Takaoka            final boolean isSinglePointer) {
1666f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard        mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer, getCurrentAutoCapsState(),
1667f091c491ea8259ea696186ea6d97e6ce0c4c3597Jean Chalard                getCurrentRecapitalizeState());
1668ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        hapticAndAudioFeedback(primaryCode, repeatCount);
1669923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1670923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1671f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka    // Callback of the {@link KeyboardActionListener}. This is called when a key is released;
1672ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    // press matching call is {@link #onPressKey(int,int,boolean)} above.
16735a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    @Override
1674f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    public void onReleaseKey(final int primaryCode, final boolean withSliding) {
1675ddc163988a7e2e910ff3cac26ed580bac123fda0Jean Chalard        mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding, getCurrentAutoCapsState(),
1676ddc163988a7e2e910ff3cac26ed580bac123fda0Jean Chalard                getCurrentRecapitalizeState());
1677923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1678a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
16795eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard    private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) {
16805eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId);
16815eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        if (null != decoder) return decoder;
16825eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        // TODO: create the decoder according to the specification
16835eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        final HardwareEventDecoder newDecoder = new HardwareKeyboardEventDecoder(deviceId);
16845eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        mHardwareEventDecoders.put(deviceId, newDecoder);
16855eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        return newDecoder;
16865eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard    }
16875eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard
1688cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    // Hooks for hardware keyboard
1689cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    @Override
16905eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard    public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
16919a438a325b28c8f8884737683237f829c7cb5a15Dmitry Torokhov        if (mEmojiAltPhysicalKeyDetector == null) {
16929a438a325b28c8f8884737683237f829c7cb5a15Dmitry Torokhov            mEmojiAltPhysicalKeyDetector = new EmojiAltPhysicalKeyDetector(
16939a438a325b28c8f8884737683237f829c7cb5a15Dmitry Torokhov                    getApplicationContext().getResources());
16949a438a325b28c8f8884737683237f829c7cb5a15Dmitry Torokhov        }
16959a438a325b28c8f8884737683237f829c7cb5a15Dmitry Torokhov        mEmojiAltPhysicalKeyDetector.onKeyDown(keyEvent);
16965a5ee95faead8a2ae749067716481e86faf5f113Tadashi G. Takaoka        if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) {
16975eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard            return super.onKeyDown(keyCode, keyEvent);
16985eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        }
16995eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        final Event event = getHardwareKeyEventDecoder(
17005eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard                keyEvent.getDeviceId()).decodeHardwareKey(keyEvent);
17015eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        // If the event is not handled by LatinIME, we just pass it to the parent implementation.
17025eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        // If it's handled, we return true because we did handle it.
17035eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        if (event.isHandled()) {
17045eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard            mInputLogic.onCodeInput(mSettings.getCurrent(), event,
170535c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                    mKeyboardSwitcher.getKeyboardShiftMode(),
170635c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                    // TODO: this is not necessarily correct for a hardware keyboard right now
170735c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                    mKeyboardSwitcher.getCurrentKeyboardScriptId(),
170835c37dbef8a65cc1e199a60090d1b4e60da69fe6Jean Chalard                    mHandler);
1709976a42b873215a669fe22709960aa1259292d75cJean Chalard            return true;
1710976a42b873215a669fe22709960aa1259292d75cJean Chalard        }
17115eac728b4aba43b8f4dabbb0dbc50acdbaaa5f22Jean Chalard        return super.onKeyDown(keyCode, keyEvent);
1712cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    }
1713cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard
1714cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    @Override
1715499153734e6dcd01ae9630bf423fadd25628339cTadashi G. Takaoka    public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) {
17161fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        if (mEmojiAltPhysicalKeyDetector == null) {
17171fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic            mEmojiAltPhysicalKeyDetector = new EmojiAltPhysicalKeyDetector(
17181fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic                    getApplicationContext().getResources());
17191fdb8f31562eeef78167585a878eb0450310036bDan Zivkovic        }
1720f7e01e866ffa89b4dd7e66c471ed9fc275a637a2Tadashi G. Takaoka        mEmojiAltPhysicalKeyDetector.onKeyUp(keyEvent);
1721499153734e6dcd01ae9630bf423fadd25628339cTadashi G. Takaoka        if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) {
1722499153734e6dcd01ae9630bf423fadd25628339cTadashi G. Takaoka            return super.onKeyUp(keyCode, keyEvent);
1723499153734e6dcd01ae9630bf423fadd25628339cTadashi G. Takaoka        }
1724499153734e6dcd01ae9630bf423fadd25628339cTadashi G. Takaoka        final long keyIdentifier = keyEvent.getDeviceId() << 32 + keyEvent.getKeyCode();
17257bd2a75ca180cb5da8ba75500163aa06f332caacJean Chalard        if (mInputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) {
1726976a42b873215a669fe22709960aa1259292d75cJean Chalard            return true;
1727976a42b873215a669fe22709960aa1259292d75cJean Chalard        }
1728499153734e6dcd01ae9630bf423fadd25628339cTadashi G. Takaoka        return super.onKeyUp(keyCode, keyEvent);
1729cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    }
1730cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard
1731cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    // onKeyDown and onKeyUp are the main events we are interested in. There are two more events
1732cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    // related to handling of hardware key events that we may want to implement in the future:
1733cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    // boolean onKeyLongPress(final int keyCode, final KeyEvent event);
1734cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard    // boolean onKeyMultiple(final int keyCode, final int count, final KeyEvent event);
1735cff28c5d5db3e0c3e97149519a3f705150aeb224Jean Chalard
17362b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka    // receive ringer mode change.
17372b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka    private final BroadcastReceiver mRingerModeChangeReceiver = new BroadcastReceiver() {
1738923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
1739f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka        public void onReceive(final Context context, final Intent intent) {
1740123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            final String action = intent.getAction();
17412b25f674f29a4c7b3c8d70bc0fbfbdc60da131c4Tadashi G. Takaoka            if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
17426f9105383a56c9ae15e35d3abf19c33d1efe5636Tadashi G. Takaoka                AudioAndHapticFeedbackManager.getInstance().onRingerModeChanged();
1743123c4a38514c003aac50caed7ad3cb6ab8f2515aTadashi G. Takaoka            }
1744923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
1745923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
1746923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
174793d2ab38577fb3d7c919bc4fd19a769f5c93e654Mohammadinamul Sheik    void launchSettings(final String extraEntryValue) {
1748ec4b6e7bb37d2f1794673dc896c14d6b554c6a0aJean Chalard        mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR);
1749ec4b6e7bb37d2f1794673dc896c14d6b554c6a0aJean Chalard        requestHideSelf(0);
1750ec4b6e7bb37d2f1794673dc896c14d6b554c6a0aJean Chalard        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
1751ec4b6e7bb37d2f1794673dc896c14d6b554c6a0aJean Chalard        if (mainKeyboardView != null) {
1752ec4b6e7bb37d2f1794673dc896c14d6b554c6a0aJean Chalard            mainKeyboardView.closing();
1753ec4b6e7bb37d2f1794673dc896c14d6b554c6a0aJean Chalard        }
175476cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka        final Intent intent = new Intent();
175576cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka        intent.setClass(LatinIME.this, SettingsActivity.class);
175640651c8cf7d4296927f9c49aaa57bcfc7b5372caTadashi G. Takaoka        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
175740651c8cf7d4296927f9c49aaa57bcfc7b5372caTadashi G. Takaoka                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
175840651c8cf7d4296927f9c49aaa57bcfc7b5372caTadashi G. Takaoka                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
175976cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka        intent.putExtra(SettingsActivity.EXTRA_SHOW_HOME_AS_UP, false);
176093d2ab38577fb3d7c919bc4fd19a769f5c93e654Mohammadinamul Sheik        intent.putExtra(SettingsActivity.EXTRA_ENTRY_KEY, extraEntryValue);
1761923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        startActivity(intent);
1762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
1763923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17642fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    private void showSubtypeSelectorAndSettings() {
176585996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence title = getString(R.string.english_ime_input_options);
176676cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka        // TODO: Should use new string "Select active input modes".
176776cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka        final CharSequence languageSelectionTitle = getString(R.string.language_selection_title);
176885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        final CharSequence[] items = new CharSequence[] {
176976cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka                languageSelectionTitle,
177076cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka                getString(ApplicationUtils.getActivityTitleResId(this, SettingsActivity.class))
177185996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
17725f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        final String imeId = mRichImm.getInputMethodIdOfThisIme();
17736abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka        final OnClickListener listener = new OnClickListener() {
17742fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            @Override
17752fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            public void onClick(DialogInterface di, int position) {
17762fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                di.dismiss();
17772fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                switch (position) {
177885996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka                case 0:
1779298b4240f84344bbcd70b72dfb20806ba93ffd22Tadashi G. Takaoka                    final Intent intent = IntentUtils.getInputLanguageSelectionIntent(
17805f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka                            imeId,
17812a659b8aa642b0832fa0ac9a93e0640592fcc239Jean Chalard                            Intent.FLAG_ACTIVITY_NEW_TASK
17822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
17832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
178476cffec78834a2db525608587eae1a5a7ef998ddTadashi G. Takaoka                    intent.putExtra(Intent.EXTRA_TITLE, languageSelectionTitle);
17852fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    startActivity(intent);
17862fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                    break;
1787aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                case 1:
178893d2ab38577fb3d7c919bc4fd19a769f5c93e654Mohammadinamul Sheik                    launchSettings(SettingsActivity.EXTRA_ENTRY_VALUE_LONG_PRESS_COMMA);
1789aa0458f917bb823efab6245f08c65e8f2f7327acKen Wakasa                    break;
17902fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka                }
17912fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka            }
179285996b472a0ec5fc31e57c52aa46c8c7794689bbTadashi G. Takaoka        };
17939b46ddc1d51fac37f970e108f7d93eb9ea11e1beTadashi G. Takaoka        final AlertDialog.Builder builder = new AlertDialog.Builder(
17949b46ddc1d51fac37f970e108f7d93eb9ea11e1beTadashi G. Takaoka                DialogUtils.getPlatformDialogThemeContext(this));
17959b46ddc1d51fac37f970e108f7d93eb9ea11e1beTadashi G. Takaoka        builder.setItems(items, listener).setTitle(title);
179630d5ed67d6548a4d7efa6354d41ac9719a4e4488Tadashi G. Takaoka        final AlertDialog dialog = builder.create();
179730d5ed67d6548a4d7efa6354d41ac9719a4e4488Tadashi G. Takaoka        dialog.setCancelable(true /* cancelable */);
179830d5ed67d6548a4d7efa6354d41ac9719a4e4488Tadashi G. Takaoka        dialog.setCanceledOnTouchOutside(true /* cancelable */);
179930d5ed67d6548a4d7efa6354d41ac9719a4e4488Tadashi G. Takaoka        showOptionDialog(dialog);
18002fa21f5854e1565deb139e0bf22719fecc5340bcTadashi G. Takaoka    }
1801923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1802342e81e7a6cfec8054a8978a9bb84b68e76a01b0Tadashi G. Takaoka    // TODO: Move this method out of {@link LatinIME}.
18036abc852255072e9c5741a7d8f264bec99b0ce14eTadashi G. Takaoka    private void showOptionDialog(final AlertDialog dialog) {
180427e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        final IBinder windowToken = mKeyboardSwitcher.getMainKeyboardView().getWindowToken();
180527e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        if (windowToken == null) {
180627e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka            return;
180727e48447a449d2eb534dfa2dc07060727e1a8fb0Tadashi G. Takaoka        }
180813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka
180913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        final Window window = dialog.getWindow();
181013d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        final WindowManager.LayoutParams lp = window.getAttributes();
181113d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        lp.token = windowToken;
181213d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
181313d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        window.setAttributes(lp);
181413d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
181513d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka
181613d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        mOptionsDialog = dialog;
181713d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka        dialog.show();
181813d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka    }
181913d6ecc4c275b9e9c38c7713bb2c69d37f3467f3Tadashi G. Takaoka
1820abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard    @UsedForTesting
1821107fb4c476779df16be23e245547253978c197acDan Zivkovic    SuggestedWords getSuggestedWordsForTest() {
1822dfbe2bfe089b301819039e9b3a7d2c307e6beac7Jean Chalard        // You may not use this method for anything else than debug
1823edaa83bb32e7299b5bba2c42d703701c1e2a3d5bDan Zivkovic        return DebugFlags.DEBUG_ENABLED ? mInputLogic.mSuggestedWords : null;
1824abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard    }
1825abaf5827e7a7f5f6c5d8d98e03e6b9528b0c9351Jean Chalard
18265408fec63a52015af9eefe3042eb1c435912195bJean Chalard    // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME.
18275408fec63a52015af9eefe3042eb1c435912195bJean Chalard    @UsedForTesting
1828107fb4c476779df16be23e245547253978c197acDan Zivkovic    void waitForLoadingDictionaries(final long timeout, final TimeUnit unit)
18299f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi            throws InterruptedException {
1830a1035be6d877cafda95b2761f9697474b79deeb8Keisuke Kuroyanagi        mDictionaryFacilitator.waitForLoadingDictionariesForTesting(timeout, unit);
18315408fec63a52015af9eefe3042eb1c435912195bJean Chalard    }
18325408fec63a52015af9eefe3042eb1c435912195bJean Chalard
1833c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard    // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
1834c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard    @UsedForTesting
1835107fb4c476779df16be23e245547253978c197acDan Zivkovic    void replaceDictionariesForTest(final Locale locale) {
1836adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi        final SettingsValues settingsValues = mSettings.getCurrent();
1837107fb4c476779df16be23e245547253978c197acDan Zivkovic        mDictionaryFacilitator.resetDictionaries(this, locale,
1838adfb262797023c4ca57bb470e547f90c88f638caKeisuke Kuroyanagi            settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts,
1839bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani            false /* forceReloadMainDictionary */,
1840d6a8adcb044dd8b73a1c96776a835b411a978b46Dan Zivkovic            settingsValues.mAccount, "", /* dictionaryNamePrefix */
1841bc4ae6bdc0249f9282efea5d1fe7ccfefd6f93b0Jatin Matani            this /* DictionaryInitializationListener */);
1842c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard    }
1843c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard
1844d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi    // DO NOT USE THIS for any other purpose than testing.
1845d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi    @UsedForTesting
1846107fb4c476779df16be23e245547253978c197acDan Zivkovic    void clearPersonalizedDictionariesForTest() {
1847bdd6c995cee664e6cd025235be2d00fc439afb1dDan Zivkovic        mDictionaryFacilitator.clearUserHistoryDictionary(this);
1848d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi    }
1849d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi
1850ac20253806180ad302e6bdea681d41bc74ba0722Xiaojun Bi    @UsedForTesting
1851107fb4c476779df16be23e245547253978c197acDan Zivkovic    List<InputMethodSubtype> getEnabledSubtypesForTest() {
18521fa3e9044f4bb7d1eb62118c94a2223af69c14b0Keisuke Kuroyanagi        return (mRichImm != null) ? mRichImm.getMyEnabledInputMethodSubtypeList(
18531fa3e9044f4bb7d1eb62118c94a2223af69c14b0Keisuke Kuroyanagi                true /* allowsImplicitlySelectedSubtypes */) : new ArrayList<InputMethodSubtype>();
1854ac20253806180ad302e6bdea681d41bc74ba0722Xiaojun Bi    }
1855ac20253806180ad302e6bdea681d41bc74ba0722Xiaojun Bi
185636c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi    public void dumpDictionaryForDebug(final String dictName) {
1857ea077349563d704dc3fdecf31a6f9f7f95ce4ad4Jean Chalard        if (!mDictionaryFacilitator.isActive()) {
18581c0876dc49eee44170cb86ba3d78e759d5bbd573Jean Chalard            resetDictionaryFacilitatorIfNecessary();
185936c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi        }
1860a1035be6d877cafda95b2761f9697474b79deeb8Keisuke Kuroyanagi        mDictionaryFacilitator.dumpDictionaryForDebug(dictName);
186136c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi    }
186236c7a62dffb7f5b6728fa0850c1f63aee0f14d80Keisuke Kuroyanagi
186328d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard    public void debugDumpStateAndCrashWithException(final String context) {
18641404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard        final SettingsValues settingsValues = mSettings.getCurrent();
18651404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard        final StringBuilder s = new StringBuilder(settingsValues.toString());
18661404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard        s.append("\nAttributes : ").append(settingsValues.mInputAttributes)
186728d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard                .append("\nContext : ").append(context);
186828d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard        throw new RuntimeException(s.toString());
186928d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard    }
187028d765ed901bfd1e736056db1cd807c13ef88c35Jean Chalard
18717e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka    @Override
1872f035649cb612be8b80892c510bbc137a615719b4Tadashi G. Takaoka    protected void dump(final FileDescriptor fd, final PrintWriter fout, final String[] args) {
1873923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super.dump(fd, fout, args);
1874a16ff1b19e8e012cf37a234bae67b994e805bfb1Doug Zongker
1875923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Printer p = new PrintWriterPrinter(fout);
1876923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        p.println("LatinIME state :");
18772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        p.println("  VersionCode = " + ApplicationUtils.getVersionCode(this));
18782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa        p.println("  VersionName = " + ApplicationUtils.getVersionName(this));
18793708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka        final Keyboard keyboard = mKeyboardSwitcher.getKeyboard();
1880df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka        final int keyboardMode = keyboard != null ? keyboard.mId.mMode : -1;
1881df9deffba241d3f1527092212de02f5c77a0b24aTadashi G. Takaoka        p.println("  Keyboard mode = " + keyboardMode);
1882ff0735ada807239abeb4c6105b7d01d2bcea0aedTadashi G. Takaoka        final SettingsValues settingsValues = mSettings.getCurrent();
1883367a35d377076e387a542560f033434959d72d1dJean Chalard        p.println(settingsValues.dump());
1884c809dc26a1e5667de6568ae1ef8c64269f884a4fChieu Nguyen        p.println(mDictionaryFacilitator.dump(this /* context */));
18851404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard        // TODO: Dump all settings values
1886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
18878ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa
18888ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa    public boolean shouldSwitchToOtherInputMethods() {
18898ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        // TODO: Revisit here to reorganize the settings. Probably we can/should use different
18908ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        // strategy once the implementation of
18918ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is defined well.
18928ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        final boolean fallbackValue = mSettings.getCurrent().mIncludesOtherImesInLanguageSwitchList;
18938ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        final IBinder token = getWindow().getWindow().getAttributes().token;
18948ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        if (token == null) {
18958ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa            return fallbackValue;
18968ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        }
18978ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        return mRichImm.shouldOfferSwitchingToNextInputMethod(token, fallbackValue);
18988ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa    }
18998ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa
19008ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa    public boolean shouldShowLanguageSwitchKey() {
19018ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        // TODO: Revisit here to reorganize the settings. Probably we can/should use different
19028ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        // strategy once the implementation of
19038ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} is defined well.
19048ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        final boolean fallbackValue = mSettings.getCurrent().isLanguageSwitchKeyEnabled();
19058ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        final IBinder token = getWindow().getWindow().getAttributes().token;
19068ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        if (token == null) {
19078ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa            return fallbackValue;
19088ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        }
19098ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa        return mRichImm.shouldOfferSwitchingToNextInputMethod(token, fallbackValue);
19108ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa    }
19116c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka
19126c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka    private void setNavigationBarVisibility(final boolean visible) {
191360b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawa        if (BuildCompatUtils.EFFECTIVE_SDK_INT > Build.VERSION_CODES.M) {
191460b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawa            // For N and later, IMEs can specify Color.TRANSPARENT to make the navigation bar
191560b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawa            // transparent.  For other colors the system uses the default color.
191660b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawa            getWindow().getWindow().setNavigationBarColor(
191760b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawa                    visible ? Color.BLACK : Color.TRANSPARENT);
191860b59042d1f5a1449de049a7f7adb3d6e40b8b06Yohei Yukawa        }
19196c04339c5aadb5118b0e0a8178b3d569956bbad7Seigo Nonaka    }
1920923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
1921