1988323c57bd25a58f05dfa492d9b9c8ab62c5153satok/* 2988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Copyright (C) 2011 The Android Open Source Project 3988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 4988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Licensed under the Apache License, Version 2.0 (the "License"); 5988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * you may not use this file except in compliance with the License. 6988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * You may obtain a copy of the License at 7988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 8988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * http://www.apache.org/licenses/LICENSE-2.0 9988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 10988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Unless required by applicable law or agreed to in writing, software 11988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * distributed under the License is distributed on an "AS IS" BASIS, 12988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * See the License for the specific language governing permissions and 14988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * limitations under the License. 15988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 16988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 17988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpackage com.android.server; 18988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 19988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.content.PackageMonitor; 20988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerService; 21988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSession; 22988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSessionListener; 23988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ITextServicesManager; 24988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ITextServicesSessionListener; 25988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 2603b2ea1102d9e3e9f189173878706ab04533eea3satokimport org.xmlpull.v1.XmlPullParserException; 2703b2ea1102d9e3e9f189173878706ab04533eea3satok 28988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ComponentName; 29988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Context; 30988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Intent; 31988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ServiceConnection; 32988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.PackageManager; 33988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ResolveInfo; 34988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ServiceInfo; 356be6d7548fb7c29a4d46dc985318ab2adf69f95fsatokimport android.os.Binder; 365357806980269d846a15c845a6fcc0384fb18860satokimport android.os.Bundle; 37988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.IBinder; 38988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.RemoteException; 39988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.provider.Settings; 40988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.service.textservice.SpellCheckerService; 415357806980269d846a15c845a6fcc0384fb18860satokimport android.text.TextUtils; 42988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.util.Slog; 4305f24700613fb4dce95fb6d5f8fe460d7a30c128satokimport android.view.inputmethod.InputMethodManager; 4405f24700613fb4dce95fb6d5f8fe460d7a30c128satokimport android.view.inputmethod.InputMethodSubtype; 45988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.SpellCheckerInfo; 46ada8c4e6a3da96a795f39a1028d448eb7aebfab3satokimport android.view.textservice.SpellCheckerSubtype; 47988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 4871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.io.FileDescriptor; 4903b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.io.IOException; 5071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.io.PrintWriter; 51988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.ArrayList; 52988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.HashMap; 53988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.List; 5471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.util.Map; 554e713f14419a37f385cf1509b011982bdcf67edcsatokimport java.util.concurrent.CopyOnWriteArrayList; 56988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 57988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpublic class TextServicesManagerService extends ITextServicesManager.Stub { 58988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final String TAG = TextServicesManagerService.class.getSimpleName(); 59988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final boolean DBG = false; 60988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 61988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Context mContext; 62988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mSystemReady; 63988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final TextServicesMonitor mMonitor; 64988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = 65988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerInfo>(); 66988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>(); 67988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = 68988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerBindGroup>(); 69988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 70988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void systemReady() { 71988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 72988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = true; 73988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 74988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 75988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 76988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public TextServicesManagerService(Context context) { 77988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = false; 78988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext = context; 79988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mMonitor = new TextServicesMonitor(); 80d0d7503fd3e941113094532f28986f49b11b5fdbDianne Hackborn mMonitor.register(context, null, true); 81988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 82988323c57bd25a58f05dfa492d9b9c8ab62c5153satok buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap); 83988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 84df5659d3d317b5cf351baffe3e0d4876e89678bfsatok SpellCheckerInfo sci = getCurrentSpellChecker(null); 85df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci == null) { 86df5659d3d317b5cf351baffe3e0d4876e89678bfsatok sci = findAvailSpellCheckerLocked(null, null); 87df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci != null) { 88df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // Set the current spell checker if there is one or more spell checkers 89df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // available. In this case, "sci" is the first one in the available spell 90df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // checkers. 915b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 92df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 93df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 94988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 95988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 96988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class TextServicesMonitor extends PackageMonitor { 97988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 98988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onSomePackagesChanged() { 99988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 100988323c57bd25a58f05dfa492d9b9c8ab62c5153satok buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap); 101988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Update for each locale 102988323c57bd25a58f05dfa492d9b9c8ab62c5153satok SpellCheckerInfo sci = getCurrentSpellChecker(null); 103da317ef68603dc7649f98bda495267973825e7fasatok if (sci == null) return; 104988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final String packageName = sci.getPackageName(); 105988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int change = isPackageDisappearing(packageName); 1065b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (// Package disappearing 1075b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE 1085b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok // Package modified 1095b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok || isPackageModified(packageName)) { 1105b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok sci = findAvailSpellCheckerLocked(null, packageName); 1115b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (sci != null) { 1125b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 1135b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok } 114988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 115988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 116988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 117988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 118988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 119988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static void buildSpellCheckerMapLocked(Context context, 120988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) { 121988323c57bd25a58f05dfa492d9b9c8ab62c5153satok list.clear(); 122988323c57bd25a58f05dfa492d9b9c8ab62c5153satok map.clear(); 123988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final PackageManager pm = context.getPackageManager(); 124988323c57bd25a58f05dfa492d9b9c8ab62c5153satok List<ResolveInfo> services = pm.queryIntentServices( 125988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA); 126988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int N = services.size(); 127988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < N; ++i) { 128988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ResolveInfo ri = services.get(i); 129988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ServiceInfo si = ri.serviceInfo; 130988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ComponentName compName = new ComponentName(si.packageName, si.name); 131988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) { 132988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "Skipping text service " + compName 133988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + ": it does not require the permission " 134988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + android.Manifest.permission.BIND_TEXT_SERVICE); 135988323c57bd25a58f05dfa492d9b9c8ab62c5153satok continue; 136988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 137988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (DBG) Slog.d(TAG, "Add: " + compName); 13803b2ea1102d9e3e9f189173878706ab04533eea3satok try { 13903b2ea1102d9e3e9f189173878706ab04533eea3satok final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri); 1403cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok if (sci.getSubtypeCount() <= 0) { 1413cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok Slog.w(TAG, "Skipping text service " + compName 1423cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok + ": it does not contain subtypes."); 1433cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok continue; 1443cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok } 14503b2ea1102d9e3e9f189173878706ab04533eea3satok list.add(sci); 14603b2ea1102d9e3e9f189173878706ab04533eea3satok map.put(sci.getId(), sci); 14703b2ea1102d9e3e9f189173878706ab04533eea3satok } catch (XmlPullParserException e) { 14803b2ea1102d9e3e9f189173878706ab04533eea3satok Slog.w(TAG, "Unable to load the spell checker " + compName, e); 14903b2ea1102d9e3e9f189173878706ab04533eea3satok } catch (IOException e) { 15003b2ea1102d9e3e9f189173878706ab04533eea3satok Slog.w(TAG, "Unable to load the spell checker " + compName, e); 15103b2ea1102d9e3e9f189173878706ab04533eea3satok } 152988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 153da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 154da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "buildSpellCheckerMapLocked: " + list.size() + "," + map.size()); 155da317ef68603dc7649f98bda495267973825e7fasatok } 156988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 157988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 158988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: find an appropriate spell checker for specified locale 159988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) { 160988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int spellCheckersCount = mSpellCheckerList.size(); 161988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount == 0) { 162988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "no available spell checker services found"); 163988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return null; 164988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 165988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage != null) { 166988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < spellCheckersCount; ++i) { 167988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerInfo sci = mSpellCheckerList.get(i); 168988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage.equals(sci.getPackageName())) { 169da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 170da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "findAvailSpellCheckerLocked: " + sci.getPackageName()); 171da317ef68603dc7649f98bda495267973825e7fasatok } 172988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return sci; 173988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 174988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 175988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 176988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount > 1) { 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "more than one spell checker service found, picking first"); 178988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 179988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerList.get(0); 180988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 181988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 182988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Save SpellCheckerService by supported languages. Currently only one spell 183988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // checker is saved. 184988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 185988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerInfo getCurrentSpellChecker(String locale) { 186988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 187a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final String curSpellCheckerId = 188988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Settings.Secure.getString(mContext.getContentResolver(), 189ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Settings.Secure.SELECTED_SPELL_CHECKER); 190562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 191562ab585f9e413d9696ee250e5ec02f95889a157satok Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); 192562ab585f9e413d9696ee250e5ec02f95889a157satok } 193988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (TextUtils.isEmpty(curSpellCheckerId)) { 194df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return null; 195988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 196988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerMap.get(curSpellCheckerId); 197988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 198988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 199988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 2003cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok // TODO: Respect allowImplicitlySelectedSubtype 20117150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale". 202ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok @Override 2033cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok public SpellCheckerSubtype getCurrentSpellCheckerSubtype( 2043cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok String locale, boolean allowImplicitlySelectedSubtype) { 205ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok synchronized (mSpellCheckerMap) { 206ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final String subtypeHashCodeStr = 207ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Settings.Secure.getString(mContext.getContentResolver(), 208ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE); 209ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (DBG) { 210c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr); 211ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 212ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerInfo sci = getCurrentSpellChecker(null); 213a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (sci == null || sci.getSubtypeCount() == 0) { 214a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 215a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "Subtype not found."); 216a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 217ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok return null; 218ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 219b387954a92eb6f15b7f49d5b946745f492a26363satok final int hashCode; 220b387954a92eb6f15b7f49d5b946745f492a26363satok if (!TextUtils.isEmpty(subtypeHashCodeStr)) { 221b387954a92eb6f15b7f49d5b946745f492a26363satok hashCode = Integer.valueOf(subtypeHashCodeStr); 222b387954a92eb6f15b7f49d5b946745f492a26363satok } else { 223b387954a92eb6f15b7f49d5b946745f492a26363satok hashCode = 0; 224ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 225b387954a92eb6f15b7f49d5b946745f492a26363satok if (hashCode == 0 && !allowImplicitlySelectedSubtype) { 226fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok return null; 227fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok } 22805f24700613fb4dce95fb6d5f8fe460d7a30c128satok String candidateLocale = null; 22905f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (hashCode == 0) { 23005f24700613fb4dce95fb6d5f8fe460d7a30c128satok // Spell checker language settings == "auto" 23105f24700613fb4dce95fb6d5f8fe460d7a30c128satok final InputMethodManager imm = 23205f24700613fb4dce95fb6d5f8fe460d7a30c128satok (InputMethodManager)mContext.getSystemService(Context.INPUT_METHOD_SERVICE); 23305f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (imm != null) { 23405f24700613fb4dce95fb6d5f8fe460d7a30c128satok final InputMethodSubtype currentInputMethodSubtype = 23505f24700613fb4dce95fb6d5f8fe460d7a30c128satok imm.getCurrentInputMethodSubtype(); 23605f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (currentInputMethodSubtype != null) { 23705f24700613fb4dce95fb6d5f8fe460d7a30c128satok final String localeString = currentInputMethodSubtype.getLocale(); 23805f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (!TextUtils.isEmpty(localeString)) { 23905f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 1. Use keyboard locale if available in the spell checker 24005f24700613fb4dce95fb6d5f8fe460d7a30c128satok candidateLocale = localeString; 24105f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 24205f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 24305f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 24405f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (candidateLocale == null) { 24505f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 2. Use System locale if available in the spell checker 24605f24700613fb4dce95fb6d5f8fe460d7a30c128satok candidateLocale = mContext.getResources().getConfiguration().locale.toString(); 24705f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 24805f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 249b387954a92eb6f15b7f49d5b946745f492a26363satok SpellCheckerSubtype candidate = null; 250ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok for (int i = 0; i < sci.getSubtypeCount(); ++i) { 251ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerSubtype scs = sci.getSubtypeAt(i); 252b387954a92eb6f15b7f49d5b946745f492a26363satok if (hashCode == 0) { 25317150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka final String scsLocale = scs.getLocale(); 25417150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka if (candidateLocale.equals(scsLocale)) { 255b387954a92eb6f15b7f49d5b946745f492a26363satok return scs; 256b387954a92eb6f15b7f49d5b946745f492a26363satok } else if (candidate == null) { 2577018a90c323a7f0deb37939d5505ff112ac637f5satok if (candidateLocale.length() >= 2 && scsLocale.length() >= 2 2587018a90c323a7f0deb37939d5505ff112ac637f5satok && candidateLocale.startsWith(scsLocale)) { 25905f24700613fb4dce95fb6d5f8fe460d7a30c128satok // Fall back to the applicable language 260b387954a92eb6f15b7f49d5b946745f492a26363satok candidate = scs; 261b387954a92eb6f15b7f49d5b946745f492a26363satok } 262b387954a92eb6f15b7f49d5b946745f492a26363satok } 263b387954a92eb6f15b7f49d5b946745f492a26363satok } else if (scs.hashCode() == hashCode) { 264a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 26570deff4c107963164f8b88365909fd30ab5e6526satok Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale 26670deff4c107963164f8b88365909fd30ab5e6526satok + ", " + scs.getLocale()); 267a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 26805f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 3. Use the user specified spell check language 269ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok return scs; 270ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 271ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 27205f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 4. Fall back to the applicable language and return it if not null 27305f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 5. Simply just return it even if it's null which means we could find no suitable 27405f24700613fb4dce95fb6d5f8fe460d7a30c128satok // spell check languages 275b387954a92eb6f15b7f49d5b946745f492a26363satok return candidate; 276ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 277ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 278ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 279988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 2805b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok public void getSpellCheckerService(String sciId, String locale, 2815357806980269d846a15c845a6fcc0384fb18860satok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 2825357806980269d846a15c845a6fcc0384fb18860satok Bundle bundle) { 283988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 284988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 285988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 2865b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) { 287988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.e(TAG, "getSpellCheckerService: Invalid input."); 288988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 289988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 290988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 291988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSpellCheckerMap.containsKey(sciId)) { 292988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 293988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 2945b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok final SpellCheckerInfo sci = mSpellCheckerMap.get(sciId); 295df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final int uid = Binder.getCallingUid(); 296988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mSpellCheckerBindGroups.containsKey(sciId)) { 2976be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId); 2986be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup != null) { 2996be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalDeathRecipient recipient = 3006be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.get(sciId).addListener( 3015357806980269d846a15c845a6fcc0384fb18860satok tsListener, locale, scListener, uid, bundle); 3026be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (recipient == null) { 3036be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 3046be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "Didn't create a death recipient."); 3056be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3066be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 3076be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3086be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup.mSpellChecker == null & bindGroup.mConnected) { 3096be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "The state of the spell checker bind group is illegal."); 3106be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 3116be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } else if (bindGroup.mSpellChecker != null) { 3126be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 313df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind found. Return a spell checker session now. " 314df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + "Listeners count = " + bindGroup.mListeners.size()); 3156be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3166be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 3176be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final ISpellCheckerSession session = 3186be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.mSpellChecker.getISpellCheckerSession( 3195357806980269d846a15c845a6fcc0384fb18860satok recipient.mScLocale, recipient.mScListener, bundle); 320df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (session != null) { 321df5659d3d317b5cf351baffe3e0d4876e89678bfsatok tsListener.onServiceConnected(session); 322df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return; 323df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } else { 324df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 325df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind already expired. "); 326df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 327df5659d3d317b5cf351baffe3e0d4876e89678bfsatok bindGroup.removeAll(); 328df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 3296be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } catch (RemoteException e) { 3306be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Exception in getting spell checker session: " + e); 3316be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 3326be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3336be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3346be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 335988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 3366be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final long ident = Binder.clearCallingIdentity(); 3376be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 3385357806980269d846a15c845a6fcc0384fb18860satok startSpellCheckerServiceInnerLocked( 3395357806980269d846a15c845a6fcc0384fb18860satok sci, locale, tsListener, scListener, uid, bundle); 3406be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } finally { 3416be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Binder.restoreCallingIdentity(ident); 342988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 343988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 344988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 345988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 346988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 347a33c4fc5bed76727f1e06e522e0136101a2304cdsatok @Override 348a33c4fc5bed76727f1e06e522e0136101a2304cdsatok public boolean isSpellCheckerEnabled() { 349a33c4fc5bed76727f1e06e522e0136101a2304cdsatok synchronized(mSpellCheckerMap) { 350a33c4fc5bed76727f1e06e522e0136101a2304cdsatok return isSpellCheckerEnabledLocked(); 351a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 352a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 353a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 3546be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale, 355df5659d3d317b5cf351baffe3e0d4876e89678bfsatok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 3565357806980269d846a15c845a6fcc0384fb18860satok int uid, Bundle bundle) { 357df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 358df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Start spell checker session inner locked."); 359df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 3606be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final String sciId = info.getId(); 3616be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalServiceConnection connection = new InternalServiceConnection( 362060677f4686a93d92117d7d472e754423a368bdbsatok sciId, locale, bundle); 3636be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); 3646be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok serviceIntent.setComponent(info.getComponent()); 3656be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 3666be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "bind service: " + info.getId()); 3676be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3686be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { 3696be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Failed to get a spell checker service."); 3706be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 3716be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3726be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup group = new SpellCheckerBindGroup( 3735357806980269d846a15c845a6fcc0384fb18860satok connection, tsListener, locale, scListener, uid, bundle); 3746be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.put(sciId, group); 3756be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 3766be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 377988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 378562ab585f9e413d9696ee250e5ec02f95889a157satok public SpellCheckerInfo[] getEnabledSpellCheckers() { 379da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 380da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "getEnabledSpellCheckers: " + mSpellCheckerList.size()); 381da317ef68603dc7649f98bda495267973825e7fasatok for (int i = 0; i < mSpellCheckerList.size(); ++i) { 382da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "EnabledSpellCheckers: " + mSpellCheckerList.get(i).getPackageName()); 383da317ef68603dc7649f98bda495267973825e7fasatok } 384da317ef68603dc7649f98bda495267973825e7fasatok } 385562ab585f9e413d9696ee250e5ec02f95889a157satok return mSpellCheckerList.toArray(new SpellCheckerInfo[mSpellCheckerList.size()]); 386562ab585f9e413d9696ee250e5ec02f95889a157satok } 387562ab585f9e413d9696ee250e5ec02f95889a157satok 388562ab585f9e413d9696ee250e5ec02f95889a157satok @Override 389988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { 390da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 391da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "FinishSpellCheckerService"); 392da317ef68603dc7649f98bda495267973825e7fasatok } 393988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 3944c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok final ArrayList<SpellCheckerBindGroup> removeList = 3954c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok new ArrayList<SpellCheckerBindGroup>(); 396988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { 397988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (group == null) continue; 3984c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok // Use removeList to avoid modifying mSpellCheckerBindGroups in this loop. 3994c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok removeList.add(group); 4004c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok } 4014c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok final int removeSize = removeList.size(); 4024c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok for (int i = 0; i < removeSize; ++i) { 4034c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok removeList.get(i).removeListener(listener); 404988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 405988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 406988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 407988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 408df5659d3d317b5cf351baffe3e0d4876e89678bfsatok @Override 409ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok public void setCurrentSpellChecker(String locale, String sciId) { 410df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 411df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (mContext.checkCallingOrSelfPermission( 412df5659d3d317b5cf351baffe3e0d4876e89678bfsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 413df5659d3d317b5cf351baffe3e0d4876e89678bfsatok != PackageManager.PERMISSION_GRANTED) { 414df5659d3d317b5cf351baffe3e0d4876e89678bfsatok throw new SecurityException( 415df5659d3d317b5cf351baffe3e0d4876e89678bfsatok "Requires permission " 416df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 417df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 4185b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sciId); 419df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 420df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 421df5659d3d317b5cf351baffe3e0d4876e89678bfsatok 422ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok @Override 423ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok public void setCurrentSpellCheckerSubtype(String locale, int hashCode) { 424ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok synchronized(mSpellCheckerMap) { 425ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (mContext.checkCallingOrSelfPermission( 426ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok android.Manifest.permission.WRITE_SECURE_SETTINGS) 427ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok != PackageManager.PERMISSION_GRANTED) { 428ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok throw new SecurityException( 429ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok "Requires permission " 430ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 431ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 432a33c4fc5bed76727f1e06e522e0136101a2304cdsatok setCurrentSpellCheckerSubtypeLocked(hashCode); 433a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 434a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 435a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 436a33c4fc5bed76727f1e06e522e0136101a2304cdsatok @Override 437a33c4fc5bed76727f1e06e522e0136101a2304cdsatok public void setSpellCheckerEnabled(boolean enabled) { 438a33c4fc5bed76727f1e06e522e0136101a2304cdsatok synchronized(mSpellCheckerMap) { 439a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (mContext.checkCallingOrSelfPermission( 440a33c4fc5bed76727f1e06e522e0136101a2304cdsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 441a33c4fc5bed76727f1e06e522e0136101a2304cdsatok != PackageManager.PERMISSION_GRANTED) { 442a33c4fc5bed76727f1e06e522e0136101a2304cdsatok throw new SecurityException( 443a33c4fc5bed76727f1e06e522e0136101a2304cdsatok "Requires permission " 444a33c4fc5bed76727f1e06e522e0136101a2304cdsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 445a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 446a33c4fc5bed76727f1e06e522e0136101a2304cdsatok setSpellCheckerEnabledLocked(enabled); 447ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 448ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 449ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 4505b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok private void setCurrentSpellCheckerLocked(String sciId) { 451562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 4525b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok Slog.w(TAG, "setCurrentSpellChecker: " + sciId); 453562ab585f9e413d9696ee250e5ec02f95889a157satok } 4545b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || !mSpellCheckerMap.containsKey(sciId)) return; 455f39daef102f2dff7517e257eb25c2e3677247e83satok final SpellCheckerInfo currentSci = getCurrentSpellChecker(null); 456f39daef102f2dff7517e257eb25c2e3677247e83satok if (currentSci != null && currentSci.getId().equals(sciId)) { 457f39daef102f2dff7517e257eb25c2e3677247e83satok // Do nothing if the current spell checker is same as new spell checker. 458f39daef102f2dff7517e257eb25c2e3677247e83satok return; 459f39daef102f2dff7517e257eb25c2e3677247e83satok } 460df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final long ident = Binder.clearCallingIdentity(); 461df5659d3d317b5cf351baffe3e0d4876e89678bfsatok try { 462df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Settings.Secure.putString(mContext.getContentResolver(), 463ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Settings.Secure.SELECTED_SPELL_CHECKER, sciId); 464f39daef102f2dff7517e257eb25c2e3677247e83satok setCurrentSpellCheckerSubtypeLocked(0); 465ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } finally { 466ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Binder.restoreCallingIdentity(ident); 467ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 468ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 469ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 470a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private void setCurrentSpellCheckerSubtypeLocked(int hashCode) { 471ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (DBG) { 472ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Slog.w(TAG, "setCurrentSpellCheckerSubtype: " + hashCode); 473ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 474ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerInfo sci = getCurrentSpellChecker(null); 475fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok int tempHashCode = 0; 476fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok for (int i = 0; sci != null && i < sci.getSubtypeCount(); ++i) { 477ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if(sci.getSubtypeAt(i).hashCode() == hashCode) { 478fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok tempHashCode = hashCode; 479ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok break; 480ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 481ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 482ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final long ident = Binder.clearCallingIdentity(); 483ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok try { 484ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Settings.Secure.putString(mContext.getContentResolver(), 485fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(tempHashCode)); 486df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } finally { 487df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Binder.restoreCallingIdentity(ident); 488df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 489988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 490988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 491a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private void setSpellCheckerEnabledLocked(boolean enabled) { 492a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 493a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "setSpellCheckerEnabled: " + enabled); 494a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 495a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final long ident = Binder.clearCallingIdentity(); 496a33c4fc5bed76727f1e06e522e0136101a2304cdsatok try { 497a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Settings.Secure.putInt(mContext.getContentResolver(), 498a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0); 499a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } finally { 500a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Binder.restoreCallingIdentity(ident); 501a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 502a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 503a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 504a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private boolean isSpellCheckerEnabledLocked() { 505a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final long ident = Binder.clearCallingIdentity(); 506a33c4fc5bed76727f1e06e522e0136101a2304cdsatok try { 507a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final boolean retval = Settings.Secure.getInt(mContext.getContentResolver(), 508a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Settings.Secure.SPELL_CHECKER_ENABLED, 1) == 1; 509a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 510a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "getSpellCheckerEnabled: " + retval); 511a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 512a33c4fc5bed76727f1e06e522e0136101a2304cdsatok return retval; 513a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } finally { 514a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Binder.restoreCallingIdentity(ident); 515a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 516a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 517a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 51871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn @Override 51971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 52071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 52171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn != PackageManager.PERMISSION_GRANTED) { 52271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 52371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println("Permission Denial: can't dump TextServicesManagerService from from pid=" 52471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn + Binder.getCallingPid() 52571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn + ", uid=" + Binder.getCallingUid()); 52671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn return; 52771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 52871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 52971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn synchronized(mSpellCheckerMap) { 53071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println("Current Text Services Manager state:"); 53171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(" Spell Checker Map:"); 53271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (Map.Entry<String, SpellCheckerInfo> ent : mSpellCheckerMap.entrySet()) { 53371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print(ent.getKey()); pw.println(":"); 53471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerInfo info = ent.getValue(); 53571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("id="); pw.println(info.getId()); 53671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("comp="); 53771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(info.getComponent().toShortString()); 53871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn int NS = info.getSubtypeCount(); 53971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (int i=0; i<NS; i++) { 54071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerSubtype st = info.getSubtypeAt(i); 54171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("Subtype #"); pw.print(i); pw.println(":"); 54271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("locale="); pw.println(st.getLocale()); 54371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("extraValue="); 54471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(st.getExtraValue()); 54571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 54671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 54771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(""); 54871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(" Spell Checker Bind Groups:"); 54971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (Map.Entry<String, SpellCheckerBindGroup> ent 55071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn : mSpellCheckerBindGroups.entrySet()) { 55171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerBindGroup grp = ent.getValue(); 55271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print(ent.getKey()); pw.print(" "); 55371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(grp); pw.println(":"); 55471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mInternalConnection="); 55571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(grp.mInternalConnection); 55671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mSpellChecker="); 55771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(grp.mSpellChecker); 55871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mBound="); pw.print(grp.mBound); 55971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" mConnected="); pw.println(grp.mConnected); 56071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn int NL = grp.mListeners.size(); 56171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (int i=0; i<NL; i++) { 56271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn InternalDeathRecipient listener = grp.mListeners.get(i); 56371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("Listener #"); pw.print(i); pw.println(":"); 56471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mTsListener="); 56571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mTsListener); 56671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mScListener="); 56771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mScListener); 56871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mGroup="); 56971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mGroup); 57071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mScLocale="); 57171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(listener.mScLocale); 57271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" mUid="); pw.println(listener.mUid); 57371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 57471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 57571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 57671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 57771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 578988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // SpellCheckerBindGroup contains active text service session listeners. 579988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from 580988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // mSpellCheckerBindGroups 581988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class SpellCheckerBindGroup { 582df5659d3d317b5cf351baffe3e0d4876e89678bfsatok private final String TAG = SpellCheckerBindGroup.class.getSimpleName(); 5836be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private final InternalServiceConnection mInternalConnection; 5844e713f14419a37f385cf1509b011982bdcf67edcsatok private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners = 5854e713f14419a37f385cf1509b011982bdcf67edcsatok new CopyOnWriteArrayList<InternalDeathRecipient>(); 58671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn public boolean mBound; 5876be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public ISpellCheckerService mSpellChecker; 5886be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public boolean mConnected; 589988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 590988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerBindGroup(InternalServiceConnection connection, 591988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener listener, String locale, 5925357806980269d846a15c845a6fcc0384fb18860satok ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 593988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mInternalConnection = connection; 59471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mBound = true; 5956be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = false; 5965357806980269d846a15c845a6fcc0384fb18860satok addListener(listener, locale, scListener, uid, bundle); 597988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 598988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 599988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ISpellCheckerService spellChecker) { 600da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 601da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "onServiceConnected"); 602da317ef68603dc7649f98bda495267973825e7fasatok } 6034e713f14419a37f385cf1509b011982bdcf67edcsatok 6044e713f14419a37f385cf1509b011982bdcf67edcsatok for (InternalDeathRecipient listener : mListeners) { 6054e713f14419a37f385cf1509b011982bdcf67edcsatok try { 6064e713f14419a37f385cf1509b011982bdcf67edcsatok final ISpellCheckerSession session = spellChecker.getISpellCheckerSession( 6074e713f14419a37f385cf1509b011982bdcf67edcsatok listener.mScLocale, listener.mScListener, listener.mBundle); 6084e713f14419a37f385cf1509b011982bdcf67edcsatok synchronized(mSpellCheckerMap) { 6094e713f14419a37f385cf1509b011982bdcf67edcsatok if (mListeners.contains(listener)) { 6104e713f14419a37f385cf1509b011982bdcf67edcsatok listener.mTsListener.onServiceConnected(session); 6114e713f14419a37f385cf1509b011982bdcf67edcsatok } 612988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 6134e713f14419a37f385cf1509b011982bdcf67edcsatok } catch (RemoteException e) { 6144e713f14419a37f385cf1509b011982bdcf67edcsatok Slog.e(TAG, "Exception in getting the spell checker session." 6154e713f14419a37f385cf1509b011982bdcf67edcsatok + "Reconnect to the spellchecker. ", e); 6164e713f14419a37f385cf1509b011982bdcf67edcsatok removeAll(); 6174e713f14419a37f385cf1509b011982bdcf67edcsatok return; 618988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 6194e713f14419a37f385cf1509b011982bdcf67edcsatok } 6204e713f14419a37f385cf1509b011982bdcf67edcsatok synchronized(mSpellCheckerMap) { 6216be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellChecker = spellChecker; 6226be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = true; 623988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 624988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 625988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 6266be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener, 6275357806980269d846a15c845a6fcc0384fb18860satok String locale, ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 628da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 629da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "addListener: " + locale); 630da317ef68603dc7649f98bda495267973825e7fasatok } 6316be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok InternalDeathRecipient recipient = null; 632988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 633988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 634988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 635988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 636988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mListeners.get(i).hasSpellCheckerListener(scListener)) { 637988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do not add the lister if the group already contains this. 6386be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return null; 639988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 640988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 6416be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok recipient = new InternalDeathRecipient( 6425357806980269d846a15c845a6fcc0384fb18860satok this, tsListener, locale, scListener, uid, bundle); 643988323c57bd25a58f05dfa492d9b9c8ab62c5153satok scListener.asBinder().linkToDeath(recipient, 0); 644df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.add(recipient); 645988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch(RemoteException e) { 646988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do nothing 647988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 648988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 649988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 6506be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return recipient; 651988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 652988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 653988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void removeListener(ISpellCheckerSessionListener listener) { 654da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 655df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "remove listener: " + listener.hashCode()); 656da317ef68603dc7649f98bda495267973825e7fasatok } 657988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 658988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 659988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ArrayList<InternalDeathRecipient> removeList = 660988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new ArrayList<InternalDeathRecipient>(); 661988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 662988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final InternalDeathRecipient tempRecipient = mListeners.get(i); 663988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if(tempRecipient.hasSpellCheckerListener(listener)) { 664df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 665df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "found existing listener."); 666df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 667988323c57bd25a58f05dfa492d9b9c8ab62c5153satok removeList.add(tempRecipient); 668988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 669988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 670988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int removeSize = removeList.size(); 671988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < removeSize; ++i) { 672df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 673df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Remove " + removeList.get(i)); 674df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 6752520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final InternalDeathRecipient idr = removeList.get(i); 6762520ed8cc3436df023a4f0ce3f436977b8ab3a99satok idr.mScListener.asBinder().unlinkToDeath(idr, 0); 6772520ed8cc3436df023a4f0ce3f436977b8ab3a99satok mListeners.remove(idr); 678988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 679988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 680988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 681988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 682988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 6834c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok // cleanLocked may remove elements from mSpellCheckerBindGroups 684988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void cleanLocked() { 685da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 686da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "cleanLocked"); 687da317ef68603dc7649f98bda495267973825e7fasatok } 68871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn // If there are no more active listeners, clean up. Only do this 68971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn // once. 69071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (mBound && mListeners.isEmpty()) { 69171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mBound = false; 692c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok final String sciId = mInternalConnection.mSciId; 69371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerBindGroup cur = mSpellCheckerBindGroups.get(sciId); 69471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (cur == this) { 695c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok if (DBG) { 696c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok Slog.d(TAG, "Remove bind group."); 697c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok } 698c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok mSpellCheckerBindGroups.remove(sciId); 6996be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 700988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext.unbindService(mInternalConnection); 701988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 702988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 7036be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 7046be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public void removeAll() { 7056be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Remove the spell checker bind unexpectedly."); 706df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 7072520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final int size = mListeners.size(); 7082520ed8cc3436df023a4f0ce3f436977b8ab3a99satok for (int i = 0; i < size; ++i) { 7092520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final InternalDeathRecipient idr = mListeners.get(i); 7102520ed8cc3436df023a4f0ce3f436977b8ab3a99satok idr.mScListener.asBinder().unlinkToDeath(idr, 0); 7112520ed8cc3436df023a4f0ce3f436977b8ab3a99satok } 712df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.clear(); 713df5659d3d317b5cf351baffe3e0d4876e89678bfsatok cleanLocked(); 714df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 7156be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 716988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 717988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 718988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalServiceConnection implements ServiceConnection { 719988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mSciId; 720988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mLocale; 7215357806980269d846a15c845a6fcc0384fb18860satok private final Bundle mBundle; 722988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalServiceConnection( 723060677f4686a93d92117d7d472e754423a368bdbsatok String id, String locale, Bundle bundle) { 724988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSciId = id; 725988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mLocale = locale; 7265357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 727988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 728988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 729988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 730988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ComponentName name, IBinder service) { 731988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 7326be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 7336be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "onServiceConnected: " + name); 7346be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 735988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service); 736988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 737c7d233d93f84fce9877c3eb645bbb515baf0dc0aDianne Hackborn if (group != null && this == group.mInternalConnection) { 738988323c57bd25a58f05dfa492d9b9c8ab62c5153satok group.onServiceConnected(spellChecker); 739988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 740988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 741988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 742988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 743988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 744988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceDisconnected(ComponentName name) { 74571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn synchronized(mSpellCheckerMap) { 74671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 7472cf1cf098513807ffd3420ae106f438e943d0cd8satok if (group != null && this == group.mInternalConnection) { 74871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mSpellCheckerBindGroups.remove(mSciId); 74971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 75071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 751988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 752988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 753988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 754988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalDeathRecipient implements IBinder.DeathRecipient { 755988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ITextServicesSessionListener mTsListener; 756988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ISpellCheckerSessionListener mScListener; 757988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final String mScLocale; 758988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerBindGroup mGroup; 759df5659d3d317b5cf351baffe3e0d4876e89678bfsatok public final int mUid; 7605357806980269d846a15c845a6fcc0384fb18860satok public final Bundle mBundle; 761988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalDeathRecipient(SpellCheckerBindGroup group, 762988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener tsListener, String scLocale, 7635357806980269d846a15c845a6fcc0384fb18860satok ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 764988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTsListener = tsListener; 765988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScListener = scListener; 766988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScLocale = scLocale; 767988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup = group; 768df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mUid = uid; 7695357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 770988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 771988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 772988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { 773df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return listener.asBinder().equals(mScListener.asBinder()); 774988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 775988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 776988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 777988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void binderDied() { 778988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup.removeListener(mScListener); 779988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 780988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 781988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 782