AndroidSpellCheckerService.java revision ecab6aff5908bfd5b34670d2e2bb3696627fa47c
1022c1cc20379767966f4915e2dea65fc0b67c0d8satok/* 2022c1cc20379767966f4915e2dea65fc0b67c0d8satok * Copyright (C) 2011 The Android Open Source Project 3022c1cc20379767966f4915e2dea65fc0b67c0d8satok * 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 7022c1cc20379767966f4915e2dea65fc0b67c0d8satok * 88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9022c1cc20379767966f4915e2dea65fc0b67c0d8satok * 10022c1cc20379767966f4915e2dea65fc0b67c0d8satok * 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. 15022c1cc20379767966f4915e2dea65fc0b67c0d8satok */ 16022c1cc20379767966f4915e2dea65fc0b67c0d8satok 17022c1cc20379767966f4915e2dea65fc0b67c0d8satokpackage com.android.inputmethod.latin.spellcheck; 18022c1cc20379767966f4915e2dea65fc0b67c0d8satok 19c160373b6a8e8a536ad8aa2798a33a41d3050f3bJean Chalardimport android.content.Intent; 20db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalardimport android.content.SharedPreferences; 21db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalardimport android.preference.PreferenceManager; 22022c1cc20379767966f4915e2dea65fc0b67c0d8satokimport android.service.textservice.SpellCheckerService; 23204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaokaimport android.text.InputType; 24204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaokaimport android.view.inputmethod.EditorInfo; 25204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 26022c1cc20379767966f4915e2dea65fc0b67c0d8satokimport android.view.textservice.SuggestionsInfo; 27022c1cc20379767966f4915e2dea65fc0b67c0d8satok 289e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.keyboard.Keyboard; 299e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.keyboard.KeyboardId; 30244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataokaimport com.android.inputmethod.keyboard.KeyboardLayoutSet; 319e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.keyboard.ProximityInfo; 329e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.latin.DictionaryFacilitator; 33d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagiimport com.android.inputmethod.latin.DictionaryFacilitatorLruCache; 34bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagiimport com.android.inputmethod.latin.NgramContext; 3559b501a05078e5a9de7cdace19c51ca693076a17Jean Chalardimport com.android.inputmethod.latin.R; 3685ddfe1317a4475269e53f62c2338c335e02e839Jean Chalardimport com.android.inputmethod.latin.RichInputMethodSubtype; 379e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; 38204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaokaimport com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; 39289299bf66de5fb0c8a378f2366c0760da27077bJean Chalardimport com.android.inputmethod.latin.utils.ScriptUtils; 409e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.latin.utils.SuggestionResults; 419e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport com.android.inputmethod.latin.WordComposer; 423234123fba901243990972158d023a5d1c273316Jean Chalard 433234123fba901243990972158d023a5d1c273316Jean Chalardimport java.util.Locale; 449e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport java.util.concurrent.ConcurrentHashMap; 459e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport java.util.concurrent.ConcurrentLinkedQueue; 469e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagiimport java.util.concurrent.Semaphore; 473234123fba901243990972158d023a5d1c273316Jean Chalard 48022c1cc20379767966f4915e2dea65fc0b67c0d8satok/** 49022c1cc20379767966f4915e2dea65fc0b67c0d8satok * Service for spell checking, using LatinIME's dictionaries and mechanisms. 50022c1cc20379767966f4915e2dea65fc0b67c0d8satok */ 51a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class AndroidSpellCheckerService extends SpellCheckerService 52db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard implements SharedPreferences.OnSharedPreferenceChangeListener { 53db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard public static final String PREF_USE_CONTACTS_KEY = "pref_spellcheck_use_contacts"; 54db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard 55204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka private static final int SPELLCHECKER_DUMMY_KEYBOARD_WIDTH = 480; 566cc318bd6a2c5993cce128d75fe753c3686331c1Keisuke Kuroyanagi private static final int SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT = 301; 57204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka 589e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private static final String DICTIONARY_NAME_PREFIX = "spellcheck_"; 599e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi 609e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private static final String[] EMPTY_STRING_ARRAY = new String[0]; 619e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi 629e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private final int MAX_NUM_OF_THREADS_READ_DICTIONARY = 2; 639e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private final Semaphore mSemaphore = new Semaphore(MAX_NUM_OF_THREADS_READ_DICTIONARY, 649e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi true /* fair */); 659e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi // TODO: Make each spell checker session has its own session id. 669e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private final ConcurrentLinkedQueue<Integer> mSessionIdPool = new ConcurrentLinkedQueue<>(); 679e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi 689e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private static final int MAX_DICTIONARY_FACILITATOR_COUNT = 3; 69d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi private final DictionaryFacilitatorLruCache mDictionaryFacilitatorCache = 70d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi new DictionaryFacilitatorLruCache(this /* context */, MAX_DICTIONARY_FACILITATOR_COUNT, 71d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi DICTIONARY_NAME_PREFIX); 729e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private final ConcurrentHashMap<Locale, Keyboard> mKeyboardCache = new ConcurrentHashMap<>(); 733234123fba901243990972158d023a5d1c273316Jean Chalard 74a409f009fa410019ad10b1134ff57393443eba33Jean Chalard // The threshold for a suggestion to be considered "recommended". 750028ed3627ff4f37a62a80f3b2c857e373cd5090satok private float mRecommendedThreshold; 769e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi // TODO: make a spell checker option to block offensive words or not 779e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private final SettingsValuesForSuggestion mSettingsValuesForSuggestion = 789e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi new SettingsValuesForSuggestion(true /* blockPotentiallyOffensive */, 799e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi true /* spaceAwareGestureEnabled */, 809e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi null /* additionalFeaturesSettingValues */); 8159b501a05078e5a9de7cdace19c51ca693076a17Jean Chalard 8284ed0966417d93b07c4da2b295244b160d223ce9Satoshi Kataoka public static final String SINGLE_QUOTE = "\u0027"; 8384ed0966417d93b07c4da2b295244b160d223ce9Satoshi Kataoka public static final String APOSTROPHE = "\u2019"; 841830cd1dc8259aa57175f1cf2a3d8797a7a35935Jean Chalard 859e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi public AndroidSpellCheckerService() { 869e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi super(); 879e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi for (int i = 0; i < MAX_NUM_OF_THREADS_READ_DICTIONARY; i++) { 889e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSessionIdPool.add(i); 899e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 909e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 919e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi 9259b501a05078e5a9de7cdace19c51ca693076a17Jean Chalard @Override public void onCreate() { 9359b501a05078e5a9de7cdace19c51ca693076a17Jean Chalard super.onCreate(); 94a409f009fa410019ad10b1134ff57393443eba33Jean Chalard mRecommendedThreshold = 950028ed3627ff4f37a62a80f3b2c857e373cd5090satok Float.parseFloat(getString(R.string.spellchecker_recommended_threshold_value)); 96db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 97db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard prefs.registerOnSharedPreferenceChangeListener(this); 98db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY); 99db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard } 100db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard 1011467fa0c2642e05aef6f588eef0f704b6da3aee2Keisuke Kuroyanagi public float getRecommendedThreshold() { 1021467fa0c2642e05aef6f588eef0f704b6da3aee2Keisuke Kuroyanagi return mRecommendedThreshold; 1031467fa0c2642e05aef6f588eef0f704b6da3aee2Keisuke Kuroyanagi } 1041467fa0c2642e05aef6f588eef0f704b6da3aee2Keisuke Kuroyanagi 105244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka private static String getKeyboardLayoutNameForScript(final int script) { 106244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka switch (script) { 107289299bf66de5fb0c8a378f2366c0760da27077bJean Chalard case ScriptUtils.SCRIPT_LATIN: 108244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka return "qwerty"; 109289299bf66de5fb0c8a378f2366c0760da27077bJean Chalard case ScriptUtils.SCRIPT_CYRILLIC: 110244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka return "east_slavic"; 111289299bf66de5fb0c8a378f2366c0760da27077bJean Chalard case ScriptUtils.SCRIPT_GREEK: 112244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka return "greek"; 113244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka default: 114244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka throw new RuntimeException("Wrong script supplied: " + script); 115244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka } 116244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka } 117244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka 118db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard @Override 119db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { 120db5aedb5a5eea5224e5a732b689c97eead2e35f4Jean Chalard if (!PREF_USE_CONTACTS_KEY.equals(key)) return; 1219e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi final boolean useContactsDictionary = prefs.getBoolean(PREF_USE_CONTACTS_KEY, true); 122d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi mDictionaryFacilitatorCache.setUseContactsDictionary(useContactsDictionary); 12359b501a05078e5a9de7cdace19c51ca693076a17Jean Chalard } 12459b501a05078e5a9de7cdace19c51ca693076a17Jean Chalard 1255bcf8ee66ceb38675a6b70fefcb574978e0fae92satok @Override 1265bcf8ee66ceb38675a6b70fefcb574978e0fae92satok public Session createSession() { 12737b19ffe6c9d8335cc0e1c1c50f5b08c778b287cSatoshi Kataoka // Should not refer to AndroidSpellCheckerSession directly considering 12837b19ffe6c9d8335cc0e1c1c50f5b08c778b287cSatoshi Kataoka // that AndroidSpellCheckerSession may be overlaid. 12937b19ffe6c9d8335cc0e1c1c50f5b08c778b287cSatoshi Kataoka return AndroidSpellCheckerSessionFactory.newInstance(this); 1305bcf8ee66ceb38675a6b70fefcb574978e0fae92satok } 1315bcf8ee66ceb38675a6b70fefcb574978e0fae92satok 132df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard /** 133df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard * Returns an empty SuggestionsInfo with flags signaling the word is not in the dictionary. 134df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard * @param reportAsTypo whether this should include the flag LOOKS_LIKE_TYPO, for red underline. 135df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard * @return the empty SuggestionsInfo with the appropriate flags set. 136df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard */ 137df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard public static SuggestionsInfo getNotInDictEmptySuggestions(final boolean reportAsTypo) { 138df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard return new SuggestionsInfo(reportAsTypo ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0, 139df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard EMPTY_STRING_ARRAY); 140cba1af9c5626a2cb1e611735deb72db72d02c4c1Jean Chalard } 141cba1af9c5626a2cb1e611735deb72db72d02c4c1Jean Chalard 142df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard /** 143df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard * Returns an empty suggestionInfo with flags signaling the word is in the dictionary. 144df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard * @return the empty SuggestionsInfo with the appropriate flags set. 145df33982fce6312203ed7446926f31ed92a8ae1caJean Chalard */ 14684ed0966417d93b07c4da2b295244b160d223ce9Satoshi Kataoka public static SuggestionsInfo getInDictEmptySuggestions() { 147cba1af9c5626a2cb1e611735deb72db72d02c4c1Jean Chalard return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY, 148cba1af9c5626a2cb1e611735deb72db72d02c4c1Jean Chalard EMPTY_STRING_ARRAY); 149cba1af9c5626a2cb1e611735deb72db72d02c4c1Jean Chalard } 150cba1af9c5626a2cb1e611735deb72db72d02c4c1Jean Chalard 1519e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi public boolean isValidWord(final Locale locale, final String word) { 1529e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.acquireUninterruptibly(); 1539e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi try { 1549e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi DictionaryFacilitator dictionaryFacilitatorForLocale = 155d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi mDictionaryFacilitatorCache.get(locale); 1569e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi return dictionaryFacilitatorForLocale.isValidWord(word, false /* igroreCase */); 1579e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } finally { 1589e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.release(); 1599e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 1608403611960cd0b2a40b77275c536e8088c098830Jean Chalard } 1618403611960cd0b2a40b77275c536e8088c098830Jean Chalard 1629e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi public SuggestionResults getSuggestionResults(final Locale locale, final WordComposer composer, 163bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi final NgramContext ngramContext, final ProximityInfo proximityInfo) { 1649e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi Integer sessionId = null; 1659e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.acquireUninterruptibly(); 1669e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi try { 1679e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi sessionId = mSessionIdPool.poll(); 1689e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi DictionaryFacilitator dictionaryFacilitatorForLocale = 169d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi mDictionaryFacilitatorCache.get(locale); 170bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi return dictionaryFacilitatorForLocale.getSuggestionResults(composer, ngramContext, 171ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalard proximityInfo.getNativeProximityInfo(), mSettingsValuesForSuggestion, 172ecab6aff5908bfd5b34670d2e2bb3696627fa47cJean Chalard sessionId); 1739e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } finally { 1749e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi if (sessionId != null) { 1759e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSessionIdPool.add(sessionId); 1769e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 1779e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.release(); 1789e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 1799e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 1809e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi 1819e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi public boolean hasMainDictionaryForLocale(final Locale locale) { 1829e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.acquireUninterruptibly(); 1839e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi try { 1849e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi final DictionaryFacilitator dictionaryFacilitator = 185d267764d5abf12f95d09d1ec8f02548d992ca612Keisuke Kuroyanagi mDictionaryFacilitatorCache.get(locale); 1868cd53266229895a3e0c6618e3765d57fc5d0b392Jean Chalard return dictionaryFacilitator.hasAtLeastOneInitializedMainDictionary(); 1879e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } finally { 1889e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.release(); 1899e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 1909e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 1919e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi 1929e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi @Override 1939e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi public boolean onUnbind(final Intent intent) { 1949e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.acquireUninterruptibly(MAX_NUM_OF_THREADS_READ_DICTIONARY); 1959e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi try { 1969e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mDictionaryFacilitatorCache.evictAll(); 1979e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } finally { 1989e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mSemaphore.release(MAX_NUM_OF_THREADS_READ_DICTIONARY); 1999e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 2009e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mKeyboardCache.clear(); 2019e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi return false; 202c160373b6a8e8a536ad8aa2798a33a41d3050f3bJean Chalard } 203c160373b6a8e8a536ad8aa2798a33a41d3050f3bJean Chalard 2049e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi public Keyboard getKeyboardForLocale(final Locale locale) { 2059e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi Keyboard keyboard = mKeyboardCache.get(locale); 2069e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi if (keyboard == null) { 2079e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi keyboard = createKeyboardForLocale(locale); 2089e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi if (keyboard != null) { 2099e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi mKeyboardCache.put(locale, keyboard); 2109e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi } 2113234123fba901243990972158d023a5d1c273316Jean Chalard } 2129e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi return keyboard; 213a562767a14c7bbac95b25e69e360fc28d6ce9e33Jean Chalard } 214a562767a14c7bbac95b25e69e360fc28d6ce9e33Jean Chalard 2159e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi private Keyboard createKeyboardForLocale(final Locale locale) { 2160dab3171d442a4d0acc87cc0019bfcbd4ea4123fJean Chalard final int script = ScriptUtils.getScriptFromSpellCheckerLocale(locale); 217244a24e3685f3fc1d0cbfaf375ad137f917740c2Satoshi Kataoka final String keyboardLayoutName = getKeyboardLayoutNameForScript(script); 2183895d7f8dc2e4999947f61220b86fa148f433413Yohei Yukawa final InputMethodSubtype subtype = AdditionalSubtypeUtils.createDummyAdditionalSubtype( 2193895d7f8dc2e4999947f61220b86fa148f433413Yohei Yukawa locale.toString(), keyboardLayoutName); 220204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka final KeyboardLayoutSet keyboardLayoutSet = createKeyboardSetForSpellChecker(subtype); 2219e76304d6004c43c3149bc2df460af2a00b18a4fKeisuke Kuroyanagi return keyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET); 2223234123fba901243990972158d023a5d1c273316Jean Chalard } 223204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka 224204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka private KeyboardLayoutSet createKeyboardSetForSpellChecker(final InputMethodSubtype subtype) { 225204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka final EditorInfo editorInfo = new EditorInfo(); 226204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka editorInfo.inputType = InputType.TYPE_CLASS_TEXT; 227204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(this, editorInfo); 228204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka builder.setKeyboardGeometry( 229204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka SPELLCHECKER_DUMMY_KEYBOARD_WIDTH, SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT); 23085ddfe1317a4475269e53f62c2338c335e02e839Jean Chalard builder.setSubtype(new RichInputMethodSubtype(subtype)); 231204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka builder.setIsSpellChecker(true /* isSpellChecker */); 232204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka builder.disableTouchPositionCorrectionData(); 233204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka return builder.build(); 234204e7b140171a0a8b954cf508da139e93c3b2b2cTadashi G. Takaoka } 235022c1cc20379767966f4915e2dea65fc0b67c0d8satok} 236