18592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard/* 28592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard * Copyright (C) 2012 The Android Open Source Project 38592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard * 4ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * you may not use this file except in compliance with the License. 6ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * You may obtain a copy of the License at 78592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard * 8ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 98592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard * 108592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard * Unless required by applicable law or agreed to in writing, software 11ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * See the License for the specific language governing permissions and 14ce6bcdd1a547c9874f05a08074cafdfea16196d6Tadashi G. Takaoka * limitations under the License. 158592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard */ 168592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 178592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardpackage com.android.inputmethod.latin; 188592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 198592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.content.Context; 208592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.content.SharedPreferences; 219ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalardimport android.graphics.Point; 228592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.os.Looper; 238592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.preference.PreferenceManager; 248592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.test.ServiceTestCase; 258592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.text.InputType; 268592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.text.SpannableStringBuilder; 27f83a6821bbf3863415378ea39d3b705954318e41Jean Chalardimport android.text.style.CharacterStyle; 288592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.text.style.SuggestionSpan; 299f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagiimport android.util.Log; 308592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.view.LayoutInflater; 318592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.view.View; 326aaa105a851c1dc558a09a19fa716e9ad54270e4Tadashi G. Takaokaimport android.view.ViewGroup; 338592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.view.inputmethod.EditorInfo; 348592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.view.inputmethod.InputConnection; 352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport android.view.inputmethod.InputMethodSubtype; 36d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataokaimport android.widget.EditText; 378592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport android.widget.FrameLayout; 388592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 396d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawaimport com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; 40908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalardimport com.android.inputmethod.event.Event; 418592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport com.android.inputmethod.keyboard.Key; 428592ed408e8e81138172eefe2df28f00807a1e1fJean Chalardimport com.android.inputmethod.keyboard.Keyboard; 4381a5a10476a8ada6bbcaeb58d7c23d05f4ec1ab0Jean Chalardimport com.android.inputmethod.latin.Dictionary.PhonyDictionary; 449310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 459342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants; 4636799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardimport com.android.inputmethod.latin.common.InputPointers; 475b91b551e5ffaf2c2e691dfbd434f21c82293986Jean Chalardimport com.android.inputmethod.latin.common.LocaleUtils; 484beeb9253a06482299e0c67467531d30436a02fcJean Chalardimport com.android.inputmethod.latin.common.StringUtils; 49da973e75dcea8dac8c83d7dcc4a7a33a69bab2cdTadashi G. Takaokaimport com.android.inputmethod.latin.settings.DebugSettings; 50da973e75dcea8dac8c83d7dcc4a7a33a69bab2cdTadashi G. Takaokaimport com.android.inputmethod.latin.settings.Settings; 512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaimport com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 528592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 53c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalardimport java.util.Locale; 549f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagiimport java.util.concurrent.TimeUnit; 559cc2c94c8b4bfd4e00e5d3478b9f6e520e791bc5Tadashi G. Takaoka 56c9aaba125365cf767356a4bea442153e95bbf6a1Jean Chalardpublic class InputTestsBase extends ServiceTestCase<LatinIMEForTests> { 579f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi private static final String TAG = InputTestsBase.class.getSimpleName(); 588592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Default value for auto-correction threshold. This is the string representation of the 602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // index in the resources array of auto-correction threshold settings. 61116e58c437526ea2503564317e2731b8126acaa4Chieu Nguyen private static final boolean DEFAULT_AUTO_CORRECTION = true; 628592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 632fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // The message that sets the underline is posted with a 500 ms delay 649ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard protected static final int DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS = 500; 65cc2751ba03fad6af5da0a7b5d421963e040d690fYuichiro Hanada // The message that sets predictions is posted with a 200 ms delay 669ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS = 200; 679ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard // We wait for gesture computation for this delay 689ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard protected static final int DELAY_TO_WAIT_FOR_GESTURE_MILLIS = 200; 69ffd808b4462875a2c15d471dea020f263b833a60Dan Zivkovic // If a dictionary takes longer to load, we could have serious problems. 70ffd808b4462875a2c15d471dea020f263b833a60Dan Zivkovic private final int TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS = 5; 718592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 7281a5a10476a8ada6bbcaeb58d7c23d05f4ec1ab0Jean Chalard // Type for a test phony dictionary 7381a5a10476a8ada6bbcaeb58d7c23d05f4ec1ab0Jean Chalard private static final String TYPE_TEST = "test"; 7481a5a10476a8ada6bbcaeb58d7c23d05f4ec1ab0Jean Chalard private static final PhonyDictionary DICTIONARY_TEST = new PhonyDictionary(TYPE_TEST); 7581a5a10476a8ada6bbcaeb58d7c23d05f4ec1ab0Jean Chalard 768592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected LatinIME mLatinIME; 778592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected Keyboard mKeyboard; 78d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka protected MyEditText mEditText; 792752287c425b9be87800136bd616ee63940caaacJean Chalard protected View mInputView; 808592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected InputConnection mInputConnection; 81116e58c437526ea2503564317e2731b8126acaa4Chieu Nguyen private boolean mPreviousAutoCorrectSetting; 825455179b54eb8230577f518db082796a3055685aDan Zivkovic private boolean mPreviousBigramPredictionSettings; 838592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 848592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // A helper class to ease span tests 85f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard public static class SpanGetter { 868592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final SpannableStringBuilder mInputText; 87f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard final CharacterStyle mSpan; 888592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final int mStart; 898592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final int mEnd; 908592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // The supplied CharSequence should be an instance of SpannableStringBuilder, 91f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard // and it should contain exactly zero or one span. Otherwise, an exception 928592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // is thrown. 93f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard public SpanGetter(final CharSequence inputText, 94f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard final Class<? extends CharacterStyle> spanType) { 958592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mInputText = (SpannableStringBuilder)inputText; 96f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard final CharacterStyle[] spans = 97f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard mInputText.getSpans(0, mInputText.length(), spanType); 988592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard if (0 == spans.length) { 998592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mSpan = null; 1008592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mStart = -1; 1018592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mEnd = -1; 1028592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } else if (1 == spans.length) { 1038592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mSpan = spans[0]; 1048592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mStart = mInputText.getSpanStart(mSpan); 1058592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mEnd = mInputText.getSpanEnd(mSpan); 1068592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } else { 107f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard throw new RuntimeException("Expected one span, found " + spans.length); 1088592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 1098592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 1104262ef4e11ae2c5dc0a8db980d4996c04731bc2bDan Zivkovic public SuggestionSpan getSpan() { 1114262ef4e11ae2c5dc0a8db980d4996c04731bc2bDan Zivkovic return (SuggestionSpan) mSpan; 1124262ef4e11ae2c5dc0a8db980d4996c04731bc2bDan Zivkovic } 1138592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard public boolean isAutoCorrectionIndicator() { 114f83a6821bbf3863415378ea39d3b705954318e41Jean Chalard return (mSpan instanceof SuggestionSpan) && 1154262ef4e11ae2c5dc0a8db980d4996c04731bc2bDan Zivkovic 0 != (SuggestionSpan.FLAG_AUTO_CORRECTION & getSpan().getFlags()); 1168592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 1175d96585a388a0af8bf0e37fc38ed3d2630733ab9Jean Chalard public String[] getSuggestions() { 1184262ef4e11ae2c5dc0a8db980d4996c04731bc2bDan Zivkovic return getSpan().getSuggestions(); 1195d96585a388a0af8bf0e37fc38ed3d2630733ab9Jean Chalard } 1205d96585a388a0af8bf0e37fc38ed3d2630733ab9Jean Chalard } 1215d96585a388a0af8bf0e37fc38ed3d2630733ab9Jean Chalard 122d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // A helper class to increase control over the EditText 123d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka public static class MyEditText extends EditText { 124c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard public Locale mCurrentLocale; 125d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka public MyEditText(final Context c) { 1265d96585a388a0af8bf0e37fc38ed3d2630733ab9Jean Chalard super(c); 1275d96585a388a0af8bf0e37fc38ed3d2630733ab9Jean Chalard } 128d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka 129c43417fb5d037d49c49176ed92f995b74b861d3eSatoshi Kataoka @Override 130c43417fb5d037d49c49176ed92f995b74b861d3eSatoshi Kataoka public void onAttachedToWindow() { 131c43417fb5d037d49c49176ed92f995b74b861d3eSatoshi Kataoka // Make onAttachedToWindow "public" 132c43417fb5d037d49c49176ed92f995b74b861d3eSatoshi Kataoka super.onAttachedToWindow(); 133c43417fb5d037d49c49176ed92f995b74b861d3eSatoshi Kataoka } 134c43417fb5d037d49c49176ed92f995b74b861d3eSatoshi Kataoka 135d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // overriding hidden API in EditText 136c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard public Locale getTextServicesLocale() { 137d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // This method is necessary because EditText is asking this method for the language 138c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard // to check the spell in. If we don't override this, the spell checker will run in 139c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard // whatever language the keyboard is currently set on the test device, ignoring any 140c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard // settings we do inside the tests. 141c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard return mCurrentLocale; 142c61bed6860cf047e4ef7fd851ae82727ac230440Jean Chalard } 143d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka 144d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // overriding hidden API in EditText 145d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka public Locale getSpellCheckerLocale() { 146d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // This method is necessary because EditText is asking this method for the language 147d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // to check the spell in. If we don't override this, the spell checker will run in 148d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // whatever language the keyboard is currently set on the test device, ignoring any 149d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka // settings we do inside the tests. 150d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka return mCurrentLocale; 151d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka } 152d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka 1538592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 1548592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 1558592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard public InputTestsBase() { 156c9aaba125365cf767356a4bea442153e95bbf6a1Jean Chalard super(LatinIMEForTests.class); 1578592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 1588592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 1599f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard protected boolean setBooleanPreference(final String key, final boolean value, 1609f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard final boolean defaultValue) { 1618592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); 1629f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard final boolean previousSetting = prefs.getBoolean(key, defaultValue); 1638592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final SharedPreferences.Editor editor = prefs.edit(); 1649f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard editor.putBoolean(key, value); 1652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa editor.apply(); 1662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return previousSetting; 1672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 1682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 169cab6fa3e1b9f22135825cfdee1fb9df992e63234Dan Zivkovic protected boolean getBooleanPreference(final String key, final boolean defaultValue) { 170cab6fa3e1b9f22135825cfdee1fb9df992e63234Dan Zivkovic return PreferenceManager.getDefaultSharedPreferences(mLatinIME) 171cab6fa3e1b9f22135825cfdee1fb9df992e63234Dan Zivkovic .getBoolean(key, defaultValue); 172cab6fa3e1b9f22135825cfdee1fb9df992e63234Dan Zivkovic } 173cab6fa3e1b9f22135825cfdee1fb9df992e63234Dan Zivkovic 1742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa protected String setStringPreference(final String key, final String value, 1752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final String defaultValue) { 1762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mLatinIME); 1772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final String previousSetting = prefs.getString(key, defaultValue); 1782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa final SharedPreferences.Editor editor = prefs.edit(); 1792fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa editor.putString(key, value); 1802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa editor.apply(); 1819f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard return previousSetting; 1829f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard } 1839f7392ea9d9313b276bda59ec488cd5f994c1894Jean Chalard 184d0d3d813d23efe40598970c51bb8f064b9e3771dJean Chalard protected void setDebugMode(final boolean value) { 185d0d3d813d23efe40598970c51bb8f064b9e3771dJean Chalard setBooleanPreference(DebugSettings.PREF_DEBUG_MODE, value, false); 186d0d3d813d23efe40598970c51bb8f064b9e3771dJean Chalard setBooleanPreference(Settings.PREF_KEY_IS_INTERNAL, value, false); 1878592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 1888592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 1891404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard protected EditorInfo enrichEditorInfo(final EditorInfo ei) { 1901404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard // Some tests that inherit from us need to add some data in the EditorInfo (see 1911404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard // AppWorkaroundsTests#enrichEditorInfo() for a concrete example of this). Since we 1921404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard // control the EditorInfo, we supply a hook here for children to override. 1931404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard return ei; 1941404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard } 1951404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard 1968592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard @Override 19748a7681e064ae259b840f0e757da2d716043d893Kurt Partridge protected void setUp() throws Exception { 19848a7681e064ae259b840f0e757da2d716043d893Kurt Partridge super.setUp(); 199d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka mEditText = new MyEditText(getContext()); 20084bfde04216b471407801bf57a31687c4992bca0Jean Chalard final int inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT 20184bfde04216b471407801bf57a31687c4992bca0Jean Chalard | InputType.TYPE_TEXT_FLAG_MULTI_LINE; 202d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka mEditText.setInputType(inputType); 203d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka mEditText.setEnabled(true); 2047e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard mLastCursorPos = 0; 205161080c0291d978ed43f11c7b8939fee5fb17e06Jean Chalard if (null == Looper.myLooper()) { 206161080c0291d978ed43f11c7b8939fee5fb17e06Jean Chalard Looper.prepare(); 207161080c0291d978ed43f11c7b8939fee5fb17e06Jean Chalard } 2088592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard setupService(); 2098592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mLatinIME = getService(); 21028a59dd049bafa45de628e2cafda47bf46d9e22aJean Chalard setDebugMode(true); 2115455179b54eb8230577f518db082796a3055685aDan Zivkovic mPreviousBigramPredictionSettings = setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, 2125455179b54eb8230577f518db082796a3055685aDan Zivkovic true, true /* defaultValue */); 213116e58c437526ea2503564317e2731b8126acaa4Chieu Nguyen mPreviousAutoCorrectSetting = setBooleanPreference(Settings.PREF_AUTO_CORRECTION, 214116e58c437526ea2503564317e2731b8126acaa4Chieu Nguyen DEFAULT_AUTO_CORRECTION, DEFAULT_AUTO_CORRECTION); 2158592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mLatinIME.onCreate(); 2161404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard EditorInfo ei = new EditorInfo(); 217d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka final InputConnection ic = mEditText.onCreateInputConnection(ei); 2188592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final LayoutInflater inflater = 2198592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 2208592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard final ViewGroup vg = new FrameLayout(getContext()); 2212752287c425b9be87800136bd616ee63940caaacJean Chalard mInputView = inflater.inflate(R.layout.input_view, vg); 2221404c1af850236da4fe4ed3825b70cb228a1da5bJean Chalard ei = enrichEditorInfo(ei); 223b0561ae98063f83684706886490ba5670138fcccJean Chalard mLatinIME.onCreateInputMethodInterface().startInput(ic, ei); 2242752287c425b9be87800136bd616ee63940caaacJean Chalard mLatinIME.setInputView(mInputView); 2258592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mLatinIME.onBindInput(); 2268592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mLatinIME.onCreateInputView(); 2278592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mLatinIME.onStartInputView(ei, false); 2288592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mInputConnection = ic; 2298592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard changeLanguage("en_US"); 2307b6e999cd174f63501ccabdade5489d61107b341Jean Chalard // Run messages to avoid the messages enqueued by startInputView() and its friends 231bac89ecc508052161704ef02c26e4e1d4d5060faJean Chalard // to run on a later call and ruin things. We need to wait first because some of them 232bac89ecc508052161704ef02c26e4e1d4d5060faJean Chalard // can be posted with a delay (notably, MSG_RESUME_SUGGESTIONS) 2339ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS); 2347b6e999cd174f63501ccabdade5489d61107b341Jean Chalard runMessages(); 2358592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 2368592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 2372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa @Override 238da973e75dcea8dac8c83d7dcc4a7a33a69bab2cdTadashi G. Takaoka protected void tearDown() throws Exception { 2394370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard mLatinIME.onFinishInputView(true); 2404370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard mLatinIME.onFinishInput(); 2414370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard runMessages(); 2422fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mLatinIME.mHandler.removeAllMessages(); 2435455179b54eb8230577f518db082796a3055685aDan Zivkovic setBooleanPreference(Settings.PREF_BIGRAM_PREDICTIONS, mPreviousBigramPredictionSettings, 2445455179b54eb8230577f518db082796a3055685aDan Zivkovic true /* defaultValue */); 245116e58c437526ea2503564317e2731b8126acaa4Chieu Nguyen setBooleanPreference(Settings.PREF_AUTO_CORRECTION, mPreviousAutoCorrectSetting, 246116e58c437526ea2503564317e2731b8126acaa4Chieu Nguyen DEFAULT_AUTO_CORRECTION); 24728a59dd049bafa45de628e2cafda47bf46d9e22aJean Chalard setDebugMode(false); 2484370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard mLatinIME.recycle(); 249da973e75dcea8dac8c83d7dcc4a7a33a69bab2cdTadashi G. Takaoka super.tearDown(); 2504370ff0998d3240cfda7745d08edbdd11703b984Jean Chalard mLatinIME = null; 2512fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 2522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 2538592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // We need to run the messages added to the handler from LatinIME. The only way to do 2548592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // that is to call Looper#loop() on the right looper, so we're going to get the looper 2558592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // object and call #loop() here. The messages in the handler actually run on the UI 2568592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // thread of the keyboard by design of the handler, so we want to call it synchronously 2578592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // on the same thread that the tests are running on to mimic the actual environment as 2588592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // closely as possible. 2598592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // Now, Looper#loop() never exits in normal operation unless the Looper#quit() method 260d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard // is called, which has a lot of bad side effects. We can however just throw an exception 261d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard // in the runnable which will unwind the stack and allow us to exit. 2625f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka final class InterruptRunMessagesException extends RuntimeException { 263d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard // Empty class 264d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard } 2658592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected void runMessages() { 2668592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard mLatinIME.mHandler.post(new Runnable() { 2678592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard @Override 2688592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard public void run() { 269d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard throw new InterruptRunMessagesException(); 2708592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 2718592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard }); 2728592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard try { 273d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard Looper.loop(); 274d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard } catch (InterruptRunMessagesException e) { 275d89ed476169f3d03aa8d080c40098f4724c093adJean Chalard // Resume normal operation 2768592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 2778592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 2788592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 2798592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME. 2802282e8520a2c1984989a14fb09896536f5033b26Jean Chalard protected void typeInternal(final int codePoint, final boolean isKeyRepeat) { 2818592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // onPressKey and onReleaseKey are explicitly deactivated here, but they do happen in the 2828592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // code (although multitouch/slide input and other factors make the sequencing complicated). 2838592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // They are supposed to be entirely deconnected from the input logic from LatinIME point of 2848592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // view and only delegates to the parts of the code that care. So we don't include them here 2858592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // to keep these tests as pinpoint as possible and avoid bringing it too many dependencies, 2868592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // but keep them in mind if something breaks. Commenting them out as is should work. 287e8264cab71af545a6124fc6137837b7459145d25Tadashi G. Takaoka //mLatinIME.onPressKey(codePoint, 0 /* repeatCount */, true /* isSinglePointer */); 288e8264cab71af545a6124fc6137837b7459145d25Tadashi G. Takaoka final Key key = mKeyboard.getKey(codePoint); 289908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard final Event event; 2902282e8520a2c1984989a14fb09896536f5033b26Jean Chalard if (key == null) { 291908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard event = Event.createSoftwareKeypressEvent(codePoint, Event.NOT_A_KEY_CODE, 292908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, isKeyRepeat); 2932282e8520a2c1984989a14fb09896536f5033b26Jean Chalard } else { 2947dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int x = key.getX() + key.getWidth() / 2; 2957dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka final int y = key.getY() + key.getHeight() / 2; 2965f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka event = LatinIME.createSoftwareKeypressEvent(codePoint, x, y, isKeyRepeat); 2978592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 298908f0ed1541d1f5a9cb6d89d06ec39c219d079bdJean Chalard mLatinIME.onEvent(event); 2992282e8520a2c1984989a14fb09896536f5033b26Jean Chalard // Also see the comment at the top of this function about onReleaseKey 300e8264cab71af545a6124fc6137837b7459145d25Tadashi G. Takaoka //mLatinIME.onReleaseKey(codePoint, false /* withSliding */); 3018592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 3028592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 3032282e8520a2c1984989a14fb09896536f5033b26Jean Chalard protected void type(final int codePoint) { 3042282e8520a2c1984989a14fb09896536f5033b26Jean Chalard typeInternal(codePoint, false /* isKeyRepeat */); 3052282e8520a2c1984989a14fb09896536f5033b26Jean Chalard } 3062282e8520a2c1984989a14fb09896536f5033b26Jean Chalard 3072282e8520a2c1984989a14fb09896536f5033b26Jean Chalard protected void repeatKey(final int codePoint) { 3082282e8520a2c1984989a14fb09896536f5033b26Jean Chalard typeInternal(codePoint, true /* isKeyRepeat */); 3092282e8520a2c1984989a14fb09896536f5033b26Jean Chalard } 3102282e8520a2c1984989a14fb09896536f5033b26Jean Chalard 3118592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected void type(final String stringToType) { 3128592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) { 3138592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard type(stringToType.codePointAt(i)); 3148592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 3158592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 3168592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 3179ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard protected Point getXY(final int codePoint) { 3189ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard final Key key = mKeyboard.getKey(codePoint); 3199ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard if (key == null) { 3209ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard throw new RuntimeException("Code point not on the keyboard"); 3219ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard } 3225f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka return new Point(key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2); 3239ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard } 3249ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard 3259ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard protected void gesture(final String stringToGesture) { 3269ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard if (StringUtils.codePointCount(stringToGesture) < 2) { 3279ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard throw new RuntimeException("Can't gesture strings less than 2 chars long"); 3289ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard } 3299ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard 3309ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard mLatinIME.onStartBatchInput(); 3319ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard final int startCodePoint = stringToGesture.codePointAt(0); 3329ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard Point oldPoint = getXY(startCodePoint); 3339ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard int timestamp = 0; // In milliseconds since the start of the gesture 3349ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard final InputPointers pointers = new InputPointers(Constants.DEFAULT_GESTURE_POINTS_CAPACITY); 3359ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard pointers.addPointer(oldPoint.x, oldPoint.y, 0 /* pointerId */, timestamp); 3369ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard 3379ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard for (int i = Character.charCount(startCodePoint); i < stringToGesture.length(); 3389ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard i = stringToGesture.offsetByCodePoints(i, 1)) { 3399ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard final Point newPoint = getXY(stringToGesture.codePointAt(i)); 3409ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard // Arbitrarily 0.5s between letters and 0.1 between events. Refine this later if needed. 3419ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard final int STEPS = 5; 3429ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard for (int j = 0; j < STEPS; ++j) { 3439ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard timestamp += 100; 3449ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard pointers.addPointer(oldPoint.x + ((newPoint.x - oldPoint.x) * j) / STEPS, 3459ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard oldPoint.y + ((newPoint.y - oldPoint.y) * j) / STEPS, 3469ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard 0 /* pointerId */, timestamp); 3479ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard } 3489ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard oldPoint.x = newPoint.x; 3499ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard oldPoint.y = newPoint.y; 3509ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard mLatinIME.onUpdateBatchInput(pointers); 3519ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard } 3529ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard mLatinIME.onEndBatchInput(pointers); 3539ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard sleep(DELAY_TO_WAIT_FOR_GESTURE_MILLIS); 3549ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard runMessages(); 3559ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard } 3569ddbee8570af667b5b325ae4136853aaea85c5b9Jean Chalard 357d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi protected void waitForDictionariesToBeLoaded() { 3589f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi try { 359d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi mLatinIME.waitForLoadingDictionaries( 3609f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS, TimeUnit.SECONDS); 3619f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi } catch (InterruptedException e) { 3629f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi Log.e(TAG, "Interrupted during waiting for loading main dictionary.", e); 3638592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 3648592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 3658592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 3668592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected void changeLanguage(final String locale) { 36768730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard changeLanguage(locale, null); 36868730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard } 36968730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard 37068730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard protected void changeLanguage(final String locale, final String combiningSpec) { 37168730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard changeLanguageWithoutWait(locale, combiningSpec); 372d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi waitForDictionariesToBeLoaded(); 37372bc9ad37ed3d89ccea253542b867221a1d9a129Keisuke Kuroyanagi } 37472bc9ad37ed3d89ccea253542b867221a1d9a129Keisuke Kuroyanagi 37568730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard protected void changeLanguageWithoutWait(final String locale, final String combiningSpec) { 376d5781eef628c2cd4ac38029040746daa4679d637Satoshi Kataoka mEditText.mCurrentLocale = LocaleUtils.constructLocaleFromString(locale); 3776d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa // TODO: this is forcing a QWERTY keyboard for all locales, which is wrong. 3786d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa // It's still better than using whatever keyboard is the current one, but we 3796d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa // should actually use the default keyboard for this locale. 3806d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa // TODO: Use {@link InputMethodSubtype.InputMethodSubtypeBuilder} directly or indirectly so 3816d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa // that {@link InputMethodSubtype#isAsciiCapable} can return the correct value. 3826d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa final String EXTRA_VALUE_FOR_TEST = 3836d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY 3846d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE 3856d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE 38668730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE 38768730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard + null == combiningSpec ? "" : ("," + combiningSpec); 3886d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa final InputMethodSubtype subtype = InputMethodSubtypeCompatUtils.newInputMethodSubtype( 3896d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa R.string.subtype_no_language_qwerty, 3906d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa R.drawable.ic_ime_switcher_dark, 3916d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa locale, 3926d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa Constants.Subtype.KEYBOARD_MODE, 3936d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa EXTRA_VALUE_FOR_TEST, 3946d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa false /* isAuxiliary */, 3956d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa false /* overridesImplicitlyEnabledSubtype */, 3966d43124215ca49feb35022c602d1dae7b5f23e4dYohei Yukawa 0 /* id */); 3977fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka RichInputMethodManager.forceSubtype(subtype); 39868730d1c8eac4f3fad94a6525b343e2a136f4ffeJean Chalard mLatinIME.onCurrentInputMethodSubtypeChanged(subtype); 399a099638667f79e509a0c12d0d8457946b7df8de5Jean Chalard runMessages(); 4009fc6af325ec91a1a22c0679d374c0c3d6d03d9acTadashi G. Takaoka mKeyboard = mLatinIME.mKeyboardSwitcher.getKeyboard(); 401d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi mLatinIME.clearPersonalizedDictionariesForTest(); 4028592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 4038592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 404c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard protected void changeKeyboardLocaleAndDictLocale(final String keyboardLocale, 405c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard final String dictLocale) { 406c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard changeLanguage(keyboardLocale); 407c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard if (!keyboardLocale.equals(dictLocale)) { 4089f1fe87580adc9ca041fc044f88341fa262c82a2Keisuke Kuroyanagi mLatinIME.replaceDictionariesForTest(LocaleUtils.constructLocaleFromString(dictLocale)); 409c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard } 410d36328cecf3b0c5e7acde7bd5963ea670b8d634fKeisuke Kuroyanagi waitForDictionariesToBeLoaded(); 411c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard } 412c239a34262358e51aedb15f2e315bbe9bcd57c4bJean Chalard 4133fb5a541a44bc9a82663895fd09c342299f45b56Jean Chalard protected void pickSuggestionManually(final String suggestion) { 414ab5912959435c1901e268bc9766090e604f3523dMohammadinamul Sheik mLatinIME.pickSuggestionManually(new SuggestedWordInfo(suggestion, 415ab5912959435c1901e268bc9766090e604f3523dMohammadinamul Sheik "" /* prevWordsContext */, 1 /* score */, 41681a5a10476a8ada6bbcaeb58d7c23d05f4ec1ab0Jean Chalard SuggestedWordInfo.KIND_CORRECTION, DICTIONARY_TEST, 41724aad5a4d545e743fe43953c1a9d8141c022d355Jean Chalard SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */, 41824aad5a4d545e743fe43953c1a9d8141c022d355Jean Chalard SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */)); 4199bfb6202154e06d7156f2f374dd9359f1be4eb68Kurt Partridge } 4208592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard 4218592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard // Helper to avoid writing the try{}catch block each time 4228592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard protected static void sleep(final int milliseconds) { 4238592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard try { 4248592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard Thread.sleep(milliseconds); 4258592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } catch (InterruptedException e) {} 4268592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard } 4277e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard 4287e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard // Some helper methods to manage the mock cursor position 4297e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard // DO NOT CALL LatinIME#onUpdateSelection IF YOU WANT TO USE THOSE 4307e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard int mLastCursorPos = 0; 4317e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard /** 4327e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard * Move the cached cursor position to the passed position and send onUpdateSelection to LatinIME 4337e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard */ 4347e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard protected int sendUpdateForCursorMoveTo(final int position) { 4357e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard mInputConnection.setSelection(position, position); 4367e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard mLatinIME.onUpdateSelection(mLastCursorPos, mLastCursorPos, position, position, -1, -1); 4377e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard mLastCursorPos = position; 4387e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard return position; 4397e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard } 4407e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard 4417e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard /** 4427e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard * Move the cached cursor position by the passed amount and send onUpdateSelection to LatinIME 4437e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard */ 4447e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard protected int sendUpdateForCursorMoveBy(final int offset) { 4457e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard final int lastPos = mEditText.getText().length(); 4467e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard final int requestedPosition = mLastCursorPos + offset; 4477e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard if (requestedPosition < 0) { 4487e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard return sendUpdateForCursorMoveTo(0); 4497e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard } else if (requestedPosition > lastPos) { 4507e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard return sendUpdateForCursorMoveTo(lastPos); 4517e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard } else { 4527e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard return sendUpdateForCursorMoveTo(requestedPosition); 4537e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard } 4547e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard } 4557e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard 4567e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard /** 4577e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard * Move the cached cursor position to the end of the line and send onUpdateSelection to LatinIME 4587e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard */ 4597e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard protected int sendUpdateForCursorMoveToEndOfLine() { 4607e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard final int lastPos = mEditText.getText().length(); 4617e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard return sendUpdateForCursorMoveTo(lastPos); 4627e930bfb3a6b4a36e6e6cde5cecc76640c148fb0Jean Chalard } 4638592ed408e8e81138172eefe2df28f00807a1e1fJean Chalard} 464