TextServicesManagerService.java revision 5b9b5a9553a0276dc6b7f1f458c8d4ed03227988
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 26988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ComponentName; 27988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Context; 28988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Intent; 29988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ServiceConnection; 30988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.PackageManager; 31988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ResolveInfo; 32988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ServiceInfo; 336be6d7548fb7c29a4d46dc985318ab2adf69f95fsatokimport android.os.Binder; 34988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.IBinder; 35988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.RemoteException; 36988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.SystemClock; 37988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.provider.Settings; 38988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.text.TextUtils; 39988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.service.textservice.SpellCheckerService; 40988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.util.Log; 41988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.util.Slog; 42988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.SpellCheckerInfo; 43988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 44988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.ArrayList; 45988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.HashMap; 46988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.HashSet; 47988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.List; 48988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 49988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpublic class TextServicesManagerService extends ITextServicesManager.Stub { 50988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final String TAG = TextServicesManagerService.class.getSimpleName(); 51988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final boolean DBG = false; 52988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 53988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Context mContext; 54988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mSystemReady; 55988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final TextServicesMonitor mMonitor; 56988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = 57988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerInfo>(); 58988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>(); 59988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = 60988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerBindGroup>(); 61988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 62988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void systemReady() { 63988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 64988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = true; 65988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 66988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 67988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 68988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public TextServicesManagerService(Context context) { 69988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = false; 70988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext = context; 71988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mMonitor = new TextServicesMonitor(); 72988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mMonitor.register(context, true); 73988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 74988323c57bd25a58f05dfa492d9b9c8ab62c5153satok buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap); 75988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 76df5659d3d317b5cf351baffe3e0d4876e89678bfsatok SpellCheckerInfo sci = getCurrentSpellChecker(null); 77df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci == null) { 78df5659d3d317b5cf351baffe3e0d4876e89678bfsatok sci = findAvailSpellCheckerLocked(null, null); 79df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci != null) { 80df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // Set the current spell checker if there is one or more spell checkers 81df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // available. In this case, "sci" is the first one in the available spell 82df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // checkers. 835b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 84df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 85df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 86988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 87988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 88988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class TextServicesMonitor extends PackageMonitor { 89988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 90988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onSomePackagesChanged() { 91988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 92988323c57bd25a58f05dfa492d9b9c8ab62c5153satok buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap); 93988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Update for each locale 94988323c57bd25a58f05dfa492d9b9c8ab62c5153satok SpellCheckerInfo sci = getCurrentSpellChecker(null); 95da317ef68603dc7649f98bda495267973825e7fasatok if (sci == null) return; 96988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final String packageName = sci.getPackageName(); 97988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int change = isPackageDisappearing(packageName); 985b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (// Package disappearing 995b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE 1005b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok // Package modified 1015b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok || isPackageModified(packageName)) { 1025b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok sci = findAvailSpellCheckerLocked(null, packageName); 1035b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (sci != null) { 1045b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 1055b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok } 106988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 107988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 108988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 109988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 110988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 111988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static void buildSpellCheckerMapLocked(Context context, 112988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) { 113988323c57bd25a58f05dfa492d9b9c8ab62c5153satok list.clear(); 114988323c57bd25a58f05dfa492d9b9c8ab62c5153satok map.clear(); 115988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final PackageManager pm = context.getPackageManager(); 116988323c57bd25a58f05dfa492d9b9c8ab62c5153satok List<ResolveInfo> services = pm.queryIntentServices( 117988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA); 118988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int N = services.size(); 119988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < N; ++i) { 120988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ResolveInfo ri = services.get(i); 121988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ServiceInfo si = ri.serviceInfo; 122988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ComponentName compName = new ComponentName(si.packageName, si.name); 123988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) { 124988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "Skipping text service " + compName 125988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + ": it does not require the permission " 126988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + android.Manifest.permission.BIND_TEXT_SERVICE); 127988323c57bd25a58f05dfa492d9b9c8ab62c5153satok continue; 128988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 129988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (DBG) Slog.d(TAG, "Add: " + compName); 130988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri); 131988323c57bd25a58f05dfa492d9b9c8ab62c5153satok list.add(sci); 132988323c57bd25a58f05dfa492d9b9c8ab62c5153satok map.put(sci.getId(), sci); 133988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 134da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 135da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "buildSpellCheckerMapLocked: " + list.size() + "," + map.size()); 136da317ef68603dc7649f98bda495267973825e7fasatok } 137988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 138988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 139988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: find an appropriate spell checker for specified locale 140988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) { 141988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int spellCheckersCount = mSpellCheckerList.size(); 142988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount == 0) { 143988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "no available spell checker services found"); 144988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return null; 145988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 146988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage != null) { 147988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < spellCheckersCount; ++i) { 148988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerInfo sci = mSpellCheckerList.get(i); 149988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage.equals(sci.getPackageName())) { 150da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 151da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "findAvailSpellCheckerLocked: " + sci.getPackageName()); 152da317ef68603dc7649f98bda495267973825e7fasatok } 153988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return sci; 154988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 155988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 156988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 157988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount > 1) { 158988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "more than one spell checker service found, picking first"); 159988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 160988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerList.get(0); 161988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 162988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 163988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Save SpellCheckerService by supported languages. Currently only one spell 164988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // checker is saved. 165988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 166988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerInfo getCurrentSpellChecker(String locale) { 167988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 168da317ef68603dc7649f98bda495267973825e7fasatok String curSpellCheckerId = 169988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Settings.Secure.getString(mContext.getContentResolver(), 170988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Settings.Secure.SPELL_CHECKER_SERVICE); 171562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 172562ab585f9e413d9696ee250e5ec02f95889a157satok Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); 173562ab585f9e413d9696ee250e5ec02f95889a157satok } 174988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (TextUtils.isEmpty(curSpellCheckerId)) { 175df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return null; 176988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerMap.get(curSpellCheckerId); 178988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 179988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 180988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 181988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 1825b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok public void getSpellCheckerService(String sciId, String locale, 183988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) { 184988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 185988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 186988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 1875b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) { 188988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.e(TAG, "getSpellCheckerService: Invalid input."); 189988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 190988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 191988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 192988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSpellCheckerMap.containsKey(sciId)) { 193988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 194988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 1955b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok final SpellCheckerInfo sci = mSpellCheckerMap.get(sciId); 196df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final int uid = Binder.getCallingUid(); 197988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mSpellCheckerBindGroups.containsKey(sciId)) { 1986be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId); 1996be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup != null) { 2006be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalDeathRecipient recipient = 2016be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.get(sciId).addListener( 202df5659d3d317b5cf351baffe3e0d4876e89678bfsatok tsListener, locale, scListener, uid); 2036be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (recipient == null) { 2046be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 2056be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "Didn't create a death recipient."); 2066be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2076be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 2086be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2096be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup.mSpellChecker == null & bindGroup.mConnected) { 2106be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "The state of the spell checker bind group is illegal."); 2116be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 2126be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } else if (bindGroup.mSpellChecker != null) { 2136be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 214df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind found. Return a spell checker session now. " 215df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + "Listeners count = " + bindGroup.mListeners.size()); 2166be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2176be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 2186be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final ISpellCheckerSession session = 2196be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.mSpellChecker.getISpellCheckerSession( 2206be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok recipient.mScLocale, recipient.mScListener); 221df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (session != null) { 222df5659d3d317b5cf351baffe3e0d4876e89678bfsatok tsListener.onServiceConnected(session); 223df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return; 224df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } else { 225df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 226df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind already expired. "); 227df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 228df5659d3d317b5cf351baffe3e0d4876e89678bfsatok bindGroup.removeAll(); 229df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 2306be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } catch (RemoteException e) { 2316be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Exception in getting spell checker session: " + e); 2326be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 2336be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2346be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2356be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 236988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 2376be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final long ident = Binder.clearCallingIdentity(); 2386be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 2395b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok startSpellCheckerServiceInnerLocked(sci, locale, tsListener, scListener, uid); 2406be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } finally { 2416be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Binder.restoreCallingIdentity(ident); 242988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 243988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 244988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 245988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 246988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 2476be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale, 248df5659d3d317b5cf351baffe3e0d4876e89678bfsatok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 249df5659d3d317b5cf351baffe3e0d4876e89678bfsatok int uid) { 250df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 251df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Start spell checker session inner locked."); 252df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 2536be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final String sciId = info.getId(); 2546be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalServiceConnection connection = new InternalServiceConnection( 2556be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok sciId, locale, scListener); 2566be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); 2576be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok serviceIntent.setComponent(info.getComponent()); 2586be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 2596be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "bind service: " + info.getId()); 2606be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2616be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { 2626be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Failed to get a spell checker service."); 2636be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 2646be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2656be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup group = new SpellCheckerBindGroup( 266df5659d3d317b5cf351baffe3e0d4876e89678bfsatok connection, tsListener, locale, scListener, uid); 2676be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.put(sciId, group); 2686be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 2696be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 270988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 271562ab585f9e413d9696ee250e5ec02f95889a157satok public SpellCheckerInfo[] getEnabledSpellCheckers() { 272da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 273da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "getEnabledSpellCheckers: " + mSpellCheckerList.size()); 274da317ef68603dc7649f98bda495267973825e7fasatok for (int i = 0; i < mSpellCheckerList.size(); ++i) { 275da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "EnabledSpellCheckers: " + mSpellCheckerList.get(i).getPackageName()); 276da317ef68603dc7649f98bda495267973825e7fasatok } 277da317ef68603dc7649f98bda495267973825e7fasatok } 278562ab585f9e413d9696ee250e5ec02f95889a157satok return mSpellCheckerList.toArray(new SpellCheckerInfo[mSpellCheckerList.size()]); 279562ab585f9e413d9696ee250e5ec02f95889a157satok } 280562ab585f9e413d9696ee250e5ec02f95889a157satok 281562ab585f9e413d9696ee250e5ec02f95889a157satok @Override 282988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { 283da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 284da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "FinishSpellCheckerService"); 285da317ef68603dc7649f98bda495267973825e7fasatok } 286988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 287988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { 288988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (group == null) continue; 289988323c57bd25a58f05dfa492d9b9c8ab62c5153satok group.removeListener(listener); 290988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 291988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 292988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 293988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 294df5659d3d317b5cf351baffe3e0d4876e89678bfsatok @Override 2955b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok public void setCurrentSpellChecker(String sciId) { 296df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 297df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (mContext.checkCallingOrSelfPermission( 298df5659d3d317b5cf351baffe3e0d4876e89678bfsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 299df5659d3d317b5cf351baffe3e0d4876e89678bfsatok != PackageManager.PERMISSION_GRANTED) { 300df5659d3d317b5cf351baffe3e0d4876e89678bfsatok throw new SecurityException( 301df5659d3d317b5cf351baffe3e0d4876e89678bfsatok "Requires permission " 302df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 303df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 3045b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sciId); 305df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 306df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 307df5659d3d317b5cf351baffe3e0d4876e89678bfsatok 3085b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok private void setCurrentSpellCheckerLocked(String sciId) { 309562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 3105b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok Slog.w(TAG, "setCurrentSpellChecker: " + sciId); 311562ab585f9e413d9696ee250e5ec02f95889a157satok } 3125b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || !mSpellCheckerMap.containsKey(sciId)) return; 313df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final long ident = Binder.clearCallingIdentity(); 314df5659d3d317b5cf351baffe3e0d4876e89678bfsatok try { 315df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Settings.Secure.putString(mContext.getContentResolver(), 3165b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok Settings.Secure.SPELL_CHECKER_SERVICE, sciId); 317df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } finally { 318df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Binder.restoreCallingIdentity(ident); 319df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 320988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 321988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 322988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // SpellCheckerBindGroup contains active text service session listeners. 323988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from 324988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // mSpellCheckerBindGroups 325988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class SpellCheckerBindGroup { 326df5659d3d317b5cf351baffe3e0d4876e89678bfsatok private final String TAG = SpellCheckerBindGroup.class.getSimpleName(); 3276be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private final InternalServiceConnection mInternalConnection; 3286be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private final ArrayList<InternalDeathRecipient> mListeners = 329988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new ArrayList<InternalDeathRecipient>(); 3306be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public ISpellCheckerService mSpellChecker; 3316be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public boolean mConnected; 332988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 333988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerBindGroup(InternalServiceConnection connection, 334988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener listener, String locale, 335df5659d3d317b5cf351baffe3e0d4876e89678bfsatok ISpellCheckerSessionListener scListener, int uid) { 336988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mInternalConnection = connection; 3376be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = false; 338df5659d3d317b5cf351baffe3e0d4876e89678bfsatok addListener(listener, locale, scListener, uid); 339988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 340988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 341988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ISpellCheckerService spellChecker) { 342da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 343da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "onServiceConnected"); 344da317ef68603dc7649f98bda495267973825e7fasatok } 345988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 346988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (InternalDeathRecipient listener : mListeners) { 347988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 348988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ISpellCheckerSession session = spellChecker.getISpellCheckerSession( 349988323c57bd25a58f05dfa492d9b9c8ab62c5153satok listener.mScLocale, listener.mScListener); 350988323c57bd25a58f05dfa492d9b9c8ab62c5153satok listener.mTsListener.onServiceConnected(session); 351988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch (RemoteException e) { 352df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.e(TAG, "Exception in getting the spell checker session: " + e); 3536be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok removeAll(); 3546be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 355988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 356988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 3576be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellChecker = spellChecker; 3586be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = true; 359988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 360988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 361988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 3626be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener, 363df5659d3d317b5cf351baffe3e0d4876e89678bfsatok String locale, ISpellCheckerSessionListener scListener, int uid) { 364da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 365da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "addListener: " + locale); 366da317ef68603dc7649f98bda495267973825e7fasatok } 3676be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok InternalDeathRecipient recipient = null; 368988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 369988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 370988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 371988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 372988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mListeners.get(i).hasSpellCheckerListener(scListener)) { 373988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do not add the lister if the group already contains this. 3746be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return null; 375988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 376988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 3776be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok recipient = new InternalDeathRecipient( 378df5659d3d317b5cf351baffe3e0d4876e89678bfsatok this, tsListener, locale, scListener, uid); 379988323c57bd25a58f05dfa492d9b9c8ab62c5153satok scListener.asBinder().linkToDeath(recipient, 0); 380df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.add(recipient); 381988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch(RemoteException e) { 382988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do nothing 383988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 384988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 385988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 3866be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return recipient; 387988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 388988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 389988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void removeListener(ISpellCheckerSessionListener listener) { 390da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 391df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "remove listener: " + listener.hashCode()); 392da317ef68603dc7649f98bda495267973825e7fasatok } 393988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 394988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 395988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ArrayList<InternalDeathRecipient> removeList = 396988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new ArrayList<InternalDeathRecipient>(); 397988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 398988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final InternalDeathRecipient tempRecipient = mListeners.get(i); 399988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if(tempRecipient.hasSpellCheckerListener(listener)) { 400df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 401df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "found existing listener."); 402df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 403988323c57bd25a58f05dfa492d9b9c8ab62c5153satok removeList.add(tempRecipient); 404988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 405988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 406988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int removeSize = removeList.size(); 407988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < removeSize; ++i) { 408df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 409df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Remove " + removeList.get(i)); 410df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 411988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mListeners.remove(removeList.get(i)); 412988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 413988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 414988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 415988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 416988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 417988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void cleanLocked() { 418da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 419da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "cleanLocked"); 420da317ef68603dc7649f98bda495267973825e7fasatok } 421988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mListeners.isEmpty()) { 4226be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (mSpellCheckerBindGroups.containsKey(this)) { 4236be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.remove(this); 4246be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 425988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // Unbind service when there is no active clients. 426988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext.unbindService(mInternalConnection); 427988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 428988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4296be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 4306be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public void removeAll() { 4316be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Remove the spell checker bind unexpectedly."); 432df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 433df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.clear(); 434df5659d3d317b5cf351baffe3e0d4876e89678bfsatok cleanLocked(); 435df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 4366be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 437988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 438988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 439988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalServiceConnection implements ServiceConnection { 440988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ISpellCheckerSessionListener mListener; 441988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mSciId; 442988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mLocale; 443988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalServiceConnection( 444988323c57bd25a58f05dfa492d9b9c8ab62c5153satok String id, String locale, ISpellCheckerSessionListener listener) { 445988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSciId = id; 446988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mLocale = locale; 447988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mListener = listener; 448988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 449988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 450988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 451988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ComponentName name, IBinder service) { 452988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 4536be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 4546be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "onServiceConnected: " + name); 4556be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 456988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service); 457988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 458988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (group != null) { 459988323c57bd25a58f05dfa492d9b9c8ab62c5153satok group.onServiceConnected(spellChecker); 460988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 461988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 462988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 463988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 464988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 465988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceDisconnected(ComponentName name) { 466988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerBindGroups.remove(mSciId); 467988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 468988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 469988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 470988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalDeathRecipient implements IBinder.DeathRecipient { 471988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ITextServicesSessionListener mTsListener; 472988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ISpellCheckerSessionListener mScListener; 473988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final String mScLocale; 474988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerBindGroup mGroup; 475df5659d3d317b5cf351baffe3e0d4876e89678bfsatok public final int mUid; 476988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalDeathRecipient(SpellCheckerBindGroup group, 477988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener tsListener, String scLocale, 478df5659d3d317b5cf351baffe3e0d4876e89678bfsatok ISpellCheckerSessionListener scListener, int uid) { 479988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTsListener = tsListener; 480988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScListener = scListener; 481988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScLocale = scLocale; 482988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup = group; 483df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mUid = uid; 484988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 485988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 486988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { 487df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return listener.asBinder().equals(mScListener.asBinder()); 488988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 489988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 490988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 491988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void binderDied() { 492988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup.removeListener(mScListener); 493988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 494988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 495988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 496