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 2800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.app.ActivityManagerNative; 2900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.app.AppGlobals; 3000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.app.IUserSwitchObserver; 31988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ComponentName; 3200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.content.ContentResolver; 33988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Context; 34988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Intent; 35988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ServiceConnection; 36988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.PackageManager; 37988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ResolveInfo; 38988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ServiceInfo; 396be6d7548fb7c29a4d46dc985318ab2adf69f95fsatokimport android.os.Binder; 405357806980269d846a15c845a6fcc0384fb18860satokimport android.os.Bundle; 41988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.IBinder; 4200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.os.IRemoteCallback; 4300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.os.Process; 44988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.RemoteException; 4500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.os.UserHandle; 46988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.provider.Settings; 47988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.service.textservice.SpellCheckerService; 485357806980269d846a15c845a6fcc0384fb18860satokimport android.text.TextUtils; 49988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.util.Slog; 5005f24700613fb4dce95fb6d5f8fe460d7a30c128satokimport android.view.inputmethod.InputMethodManager; 5105f24700613fb4dce95fb6d5f8fe460d7a30c128satokimport android.view.inputmethod.InputMethodSubtype; 52988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.SpellCheckerInfo; 53ada8c4e6a3da96a795f39a1028d448eb7aebfab3satokimport android.view.textservice.SpellCheckerSubtype; 54988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 5571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.io.FileDescriptor; 5603b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.io.IOException; 5771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.io.PrintWriter; 58988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.ArrayList; 59988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.HashMap; 60988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.List; 6171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.util.Map; 624e713f14419a37f385cf1509b011982bdcf67edcsatokimport java.util.concurrent.CopyOnWriteArrayList; 63988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 64988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpublic class TextServicesManagerService extends ITextServicesManager.Stub { 65988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final String TAG = TextServicesManagerService.class.getSimpleName(); 66988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final boolean DBG = false; 67988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 68988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Context mContext; 69988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mSystemReady; 70988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final TextServicesMonitor mMonitor; 71988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = 72988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerInfo>(); 73988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>(); 74988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = 75988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerBindGroup>(); 7600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private final TextServicesSettings mSettings; 77988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 78a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov public void systemRunning() { 79988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 80988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = true; 81988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 82988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 83988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 84988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public TextServicesManagerService(Context context) { 85988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = false; 86988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext = context; 8700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka int userId = UserHandle.USER_OWNER; 8800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 8900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka ActivityManagerNative.getDefault().registerUserSwitchObserver( 9000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka new IUserSwitchObserver.Stub() { 9100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka @Override 9200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void onUserSwitching(int newUserId, IRemoteCallback reply) { 9300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka synchronized(mSpellCheckerMap) { 9400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka switchUserLocked(newUserId); 9500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 9600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (reply != null) { 9700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 9800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka reply.sendResult(null); 9900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RemoteException e) { 10000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 10100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 10200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 10300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 10400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka @Override 10500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void onUserSwitchComplete(int newUserId) throws RemoteException { 10600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 10700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka }); 10800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka userId = ActivityManagerNative.getDefault().getCurrentUser().id; 10900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RemoteException e) { 11000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e); 11100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 112988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mMonitor = new TextServicesMonitor(); 113d0d7503fd3e941113094532f28986f49b11b5fdbDianne Hackborn mMonitor.register(context, null, true); 11400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings = new TextServicesSettings(context.getContentResolver(), userId); 11500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 11600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // "switchUserLocked" initializes the states for the foreground user 11700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka switchUserLocked(userId); 11800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 11900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 12000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private void switchUserLocked(int userId) { 12100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.setCurrentUserId(userId); 12200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka unbindServiceLocked(); 12300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings); 124df5659d3d317b5cf351baffe3e0d4876e89678bfsatok SpellCheckerInfo sci = getCurrentSpellChecker(null); 125df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci == null) { 126df5659d3d317b5cf351baffe3e0d4876e89678bfsatok sci = findAvailSpellCheckerLocked(null, null); 127df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci != null) { 128df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // Set the current spell checker if there is one or more spell checkers 129df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // available. In this case, "sci" is the first one in the available spell 130df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // checkers. 1315b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 132df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 133df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 134988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 135988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 136988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class TextServicesMonitor extends PackageMonitor { 13700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private boolean isChangingPackagesOfCurrentUser() { 13800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final int userId = getChangingUserId(); 13900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final boolean retval = userId == mSettings.getCurrentUserId(); 14000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 14100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- ignore this call back from a background user: " + userId); 14200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 14300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return retval; 14400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 14500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 146988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 147988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onSomePackagesChanged() { 14800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!isChangingPackagesOfCurrentUser()) { 14900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 15000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 151988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 15200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka buildSpellCheckerMapLocked( 15300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mContext, mSpellCheckerList, mSpellCheckerMap, mSettings); 154988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Update for each locale 155988323c57bd25a58f05dfa492d9b9c8ab62c5153satok SpellCheckerInfo sci = getCurrentSpellChecker(null); 15602260e2141fac0b6a712e4ca63702e657e8e7296Satoshi Kataoka // If no spell checker is enabled, just return. The user should explicitly 15702260e2141fac0b6a712e4ca63702e657e8e7296Satoshi Kataoka // enable the spell checker. 158da317ef68603dc7649f98bda495267973825e7fasatok if (sci == null) return; 159988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final String packageName = sci.getPackageName(); 160988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int change = isPackageDisappearing(packageName); 1615b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (// Package disappearing 1625b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE 1635b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok // Package modified 1645b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok || isPackageModified(packageName)) { 1655b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok sci = findAvailSpellCheckerLocked(null, packageName); 1665b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (sci != null) { 1675b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 1685b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok } 169988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 170988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 171988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 172988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 173988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 174988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static void buildSpellCheckerMapLocked(Context context, 17500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map, 17600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka TextServicesSettings settings) { 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok list.clear(); 178988323c57bd25a58f05dfa492d9b9c8ab62c5153satok map.clear(); 179988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final PackageManager pm = context.getPackageManager(); 18000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final List<ResolveInfo> services = pm.queryIntentServicesAsUser( 18100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA, 18200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka settings.getCurrentUserId()); 183988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int N = services.size(); 184988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < N; ++i) { 185988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ResolveInfo ri = services.get(i); 186988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ServiceInfo si = ri.serviceInfo; 187988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ComponentName compName = new ComponentName(si.packageName, si.name); 188988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) { 189988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "Skipping text service " + compName 190988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + ": it does not require the permission " 191988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + android.Manifest.permission.BIND_TEXT_SERVICE); 192988323c57bd25a58f05dfa492d9b9c8ab62c5153satok continue; 193988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 194988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (DBG) Slog.d(TAG, "Add: " + compName); 19503b2ea1102d9e3e9f189173878706ab04533eea3satok try { 19603b2ea1102d9e3e9f189173878706ab04533eea3satok final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri); 1973cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok if (sci.getSubtypeCount() <= 0) { 1983cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok Slog.w(TAG, "Skipping text service " + compName 1993cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok + ": it does not contain subtypes."); 2003cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok continue; 2013cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok } 20203b2ea1102d9e3e9f189173878706ab04533eea3satok list.add(sci); 20303b2ea1102d9e3e9f189173878706ab04533eea3satok map.put(sci.getId(), sci); 20403b2ea1102d9e3e9f189173878706ab04533eea3satok } catch (XmlPullParserException e) { 20503b2ea1102d9e3e9f189173878706ab04533eea3satok Slog.w(TAG, "Unable to load the spell checker " + compName, e); 20603b2ea1102d9e3e9f189173878706ab04533eea3satok } catch (IOException e) { 20703b2ea1102d9e3e9f189173878706ab04533eea3satok Slog.w(TAG, "Unable to load the spell checker " + compName, e); 20803b2ea1102d9e3e9f189173878706ab04533eea3satok } 209988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 210da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 211da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "buildSpellCheckerMapLocked: " + list.size() + "," + map.size()); 212da317ef68603dc7649f98bda495267973825e7fasatok } 213988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 214988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 21500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // --------------------------------------------------------------------------------------- 21600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // Check whether or not this is a valid IPC. Assumes an IPC is valid when either 21700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // 1) it comes from the system process 21800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // 2) the calling process' user id is identical to the current user id TSMS thinks. 21900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private boolean calledFromValidUser() { 22000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final int uid = Binder.getCallingUid(); 22100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final int userId = UserHandle.getUserId(uid); 22200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 22300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? " 22400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID 22500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + " calling userId = " + userId + ", foreground user id = " 22600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + mSettings.getCurrentUserId()); 22700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 22800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid); 22900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka for (int i = 0; i < packageNames.length; ++i) { 23000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 23100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- process name for "+ uid + " = " + packageNames[i]); 23200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 23300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 23400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RemoteException e) { 23500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 23600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 23700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 23800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) { 23900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return true; 24000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } else { 24100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace()); 24200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return false; 24300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 24400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 24500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 24600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private boolean bindCurrentSpellCheckerService( 24700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Intent service, ServiceConnection conn, int flags) { 24800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (service == null || conn == null) { 24900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn); 25000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return false; 25100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 25227b89e6658a0d233a53f5d7ca20dc57fec82d955Amith Yamasani return mContext.bindServiceAsUser(service, conn, flags, 25327b89e6658a0d233a53f5d7ca20dc57fec82d955Amith Yamasani new UserHandle(mSettings.getCurrentUserId())); 25400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 25500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 25600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private void unbindServiceLocked() { 25700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka for (SpellCheckerBindGroup scbg : mSpellCheckerBindGroups.values()) { 25800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka scbg.removeAll(); 25900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 26000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSpellCheckerBindGroups.clear(); 26100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 26200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 263988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: find an appropriate spell checker for specified locale 264988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) { 265988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int spellCheckersCount = mSpellCheckerList.size(); 266988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount == 0) { 267988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "no available spell checker services found"); 268988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return null; 269988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 270988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage != null) { 271988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < spellCheckersCount; ++i) { 272988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerInfo sci = mSpellCheckerList.get(i); 273988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage.equals(sci.getPackageName())) { 274da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 275da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "findAvailSpellCheckerLocked: " + sci.getPackageName()); 276da317ef68603dc7649f98bda495267973825e7fasatok } 277988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return sci; 278988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 279988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 280988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 281988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount > 1) { 282988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "more than one spell checker service found, picking first"); 283988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 284988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerList.get(0); 285988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 286988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 287988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Save SpellCheckerService by supported languages. Currently only one spell 288988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // checker is saved. 289988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 290988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerInfo getCurrentSpellChecker(String locale) { 29100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TODO: Make this work even for non-current users? 29200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 29300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return null; 29400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 295988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 29600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final String curSpellCheckerId = mSettings.getSelectedSpellChecker(); 297562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 298562ab585f9e413d9696ee250e5ec02f95889a157satok Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); 299562ab585f9e413d9696ee250e5ec02f95889a157satok } 300988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (TextUtils.isEmpty(curSpellCheckerId)) { 301df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return null; 302988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 303988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerMap.get(curSpellCheckerId); 304988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 305988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 306988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 3073cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok // TODO: Respect allowImplicitlySelectedSubtype 30817150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale". 309ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok @Override 3103cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok public SpellCheckerSubtype getCurrentSpellCheckerSubtype( 3113cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok String locale, boolean allowImplicitlySelectedSubtype) { 31200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TODO: Make this work even for non-current users? 31300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 31400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return null; 31500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 316ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok synchronized (mSpellCheckerMap) { 31700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final String subtypeHashCodeStr = mSettings.getSelectedSpellCheckerSubtype(); 318ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (DBG) { 319c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr); 320ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 321ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerInfo sci = getCurrentSpellChecker(null); 322a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (sci == null || sci.getSubtypeCount() == 0) { 323a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 324a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "Subtype not found."); 325a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 326ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok return null; 327ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 328b387954a92eb6f15b7f49d5b946745f492a26363satok final int hashCode; 329b387954a92eb6f15b7f49d5b946745f492a26363satok if (!TextUtils.isEmpty(subtypeHashCodeStr)) { 330b387954a92eb6f15b7f49d5b946745f492a26363satok hashCode = Integer.valueOf(subtypeHashCodeStr); 331b387954a92eb6f15b7f49d5b946745f492a26363satok } else { 332b387954a92eb6f15b7f49d5b946745f492a26363satok hashCode = 0; 333ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 334b387954a92eb6f15b7f49d5b946745f492a26363satok if (hashCode == 0 && !allowImplicitlySelectedSubtype) { 335fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok return null; 336fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok } 33705f24700613fb4dce95fb6d5f8fe460d7a30c128satok String candidateLocale = null; 33805f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (hashCode == 0) { 33905f24700613fb4dce95fb6d5f8fe460d7a30c128satok // Spell checker language settings == "auto" 34005f24700613fb4dce95fb6d5f8fe460d7a30c128satok final InputMethodManager imm = 34105f24700613fb4dce95fb6d5f8fe460d7a30c128satok (InputMethodManager)mContext.getSystemService(Context.INPUT_METHOD_SERVICE); 34205f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (imm != null) { 34305f24700613fb4dce95fb6d5f8fe460d7a30c128satok final InputMethodSubtype currentInputMethodSubtype = 34405f24700613fb4dce95fb6d5f8fe460d7a30c128satok imm.getCurrentInputMethodSubtype(); 34505f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (currentInputMethodSubtype != null) { 34605f24700613fb4dce95fb6d5f8fe460d7a30c128satok final String localeString = currentInputMethodSubtype.getLocale(); 34705f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (!TextUtils.isEmpty(localeString)) { 34805f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 1. Use keyboard locale if available in the spell checker 34905f24700613fb4dce95fb6d5f8fe460d7a30c128satok candidateLocale = localeString; 35005f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 35105f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 35205f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 35305f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (candidateLocale == null) { 35405f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 2. Use System locale if available in the spell checker 35505f24700613fb4dce95fb6d5f8fe460d7a30c128satok candidateLocale = mContext.getResources().getConfiguration().locale.toString(); 35605f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 35705f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 358b387954a92eb6f15b7f49d5b946745f492a26363satok SpellCheckerSubtype candidate = null; 359ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok for (int i = 0; i < sci.getSubtypeCount(); ++i) { 360ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerSubtype scs = sci.getSubtypeAt(i); 361b387954a92eb6f15b7f49d5b946745f492a26363satok if (hashCode == 0) { 36217150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka final String scsLocale = scs.getLocale(); 36317150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka if (candidateLocale.equals(scsLocale)) { 364b387954a92eb6f15b7f49d5b946745f492a26363satok return scs; 365b387954a92eb6f15b7f49d5b946745f492a26363satok } else if (candidate == null) { 3667018a90c323a7f0deb37939d5505ff112ac637f5satok if (candidateLocale.length() >= 2 && scsLocale.length() >= 2 3677018a90c323a7f0deb37939d5505ff112ac637f5satok && candidateLocale.startsWith(scsLocale)) { 36805f24700613fb4dce95fb6d5f8fe460d7a30c128satok // Fall back to the applicable language 369b387954a92eb6f15b7f49d5b946745f492a26363satok candidate = scs; 370b387954a92eb6f15b7f49d5b946745f492a26363satok } 371b387954a92eb6f15b7f49d5b946745f492a26363satok } 372b387954a92eb6f15b7f49d5b946745f492a26363satok } else if (scs.hashCode() == hashCode) { 373a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 37470deff4c107963164f8b88365909fd30ab5e6526satok Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale 37570deff4c107963164f8b88365909fd30ab5e6526satok + ", " + scs.getLocale()); 376a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 37705f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 3. Use the user specified spell check language 378ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok return scs; 379ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 380ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 38105f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 4. Fall back to the applicable language and return it if not null 38205f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 5. Simply just return it even if it's null which means we could find no suitable 38305f24700613fb4dce95fb6d5f8fe460d7a30c128satok // spell check languages 384b387954a92eb6f15b7f49d5b946745f492a26363satok return candidate; 385ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 386ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 387ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 388988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 3895b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok public void getSpellCheckerService(String sciId, String locale, 3905357806980269d846a15c845a6fcc0384fb18860satok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 3915357806980269d846a15c845a6fcc0384fb18860satok Bundle bundle) { 39200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 39300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 39400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 395988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 396988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 397988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 3985b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) { 399988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.e(TAG, "getSpellCheckerService: Invalid input."); 400988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 401988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 402988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 403988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSpellCheckerMap.containsKey(sciId)) { 404988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 405988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4065b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok final SpellCheckerInfo sci = mSpellCheckerMap.get(sciId); 407df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final int uid = Binder.getCallingUid(); 408988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mSpellCheckerBindGroups.containsKey(sciId)) { 4096be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId); 4106be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup != null) { 4116be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalDeathRecipient recipient = 4126be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.get(sciId).addListener( 4135357806980269d846a15c845a6fcc0384fb18860satok tsListener, locale, scListener, uid, bundle); 4146be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (recipient == null) { 4156be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 4166be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "Didn't create a death recipient."); 4176be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4186be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 4196be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4206be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup.mSpellChecker == null & bindGroup.mConnected) { 4216be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "The state of the spell checker bind group is illegal."); 4226be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 4236be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } else if (bindGroup.mSpellChecker != null) { 4246be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 425df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind found. Return a spell checker session now. " 426df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + "Listeners count = " + bindGroup.mListeners.size()); 4276be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4286be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 4296be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final ISpellCheckerSession session = 4306be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.mSpellChecker.getISpellCheckerSession( 4315357806980269d846a15c845a6fcc0384fb18860satok recipient.mScLocale, recipient.mScListener, bundle); 432df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (session != null) { 433df5659d3d317b5cf351baffe3e0d4876e89678bfsatok tsListener.onServiceConnected(session); 434df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return; 435df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } else { 436df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 437df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind already expired. "); 438df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 439df5659d3d317b5cf351baffe3e0d4876e89678bfsatok bindGroup.removeAll(); 440df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 4416be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } catch (RemoteException e) { 4426be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Exception in getting spell checker session: " + e); 4436be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 4446be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4456be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4466be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 447988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4486be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final long ident = Binder.clearCallingIdentity(); 4496be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 4505357806980269d846a15c845a6fcc0384fb18860satok startSpellCheckerServiceInnerLocked( 4515357806980269d846a15c845a6fcc0384fb18860satok sci, locale, tsListener, scListener, uid, bundle); 4526be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } finally { 4536be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Binder.restoreCallingIdentity(ident); 454988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 455988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 456988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 457988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 458988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 459a33c4fc5bed76727f1e06e522e0136101a2304cdsatok @Override 460a33c4fc5bed76727f1e06e522e0136101a2304cdsatok public boolean isSpellCheckerEnabled() { 46100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 46200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return false; 46300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 464a33c4fc5bed76727f1e06e522e0136101a2304cdsatok synchronized(mSpellCheckerMap) { 465a33c4fc5bed76727f1e06e522e0136101a2304cdsatok return isSpellCheckerEnabledLocked(); 466a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 467a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 468a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 4696be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale, 470df5659d3d317b5cf351baffe3e0d4876e89678bfsatok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 4715357806980269d846a15c845a6fcc0384fb18860satok int uid, Bundle bundle) { 472df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 473df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Start spell checker session inner locked."); 474df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 4756be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final String sciId = info.getId(); 4766be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalServiceConnection connection = new InternalServiceConnection( 477060677f4686a93d92117d7d472e754423a368bdbsatok sciId, locale, bundle); 4786be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); 4796be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok serviceIntent.setComponent(info.getComponent()); 4806be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 4816be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "bind service: " + info.getId()); 4826be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 48300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!bindCurrentSpellCheckerService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { 4846be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Failed to get a spell checker service."); 4856be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 4866be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4876be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup group = new SpellCheckerBindGroup( 4885357806980269d846a15c845a6fcc0384fb18860satok connection, tsListener, locale, scListener, uid, bundle); 4896be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.put(sciId, group); 4906be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4916be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 492988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 493562ab585f9e413d9696ee250e5ec02f95889a157satok public SpellCheckerInfo[] getEnabledSpellCheckers() { 49400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TODO: Make this work even for non-current users? 49500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 49600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return null; 49700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 498da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 499da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "getEnabledSpellCheckers: " + mSpellCheckerList.size()); 500da317ef68603dc7649f98bda495267973825e7fasatok for (int i = 0; i < mSpellCheckerList.size(); ++i) { 501da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "EnabledSpellCheckers: " + mSpellCheckerList.get(i).getPackageName()); 502da317ef68603dc7649f98bda495267973825e7fasatok } 503da317ef68603dc7649f98bda495267973825e7fasatok } 504562ab585f9e413d9696ee250e5ec02f95889a157satok return mSpellCheckerList.toArray(new SpellCheckerInfo[mSpellCheckerList.size()]); 505562ab585f9e413d9696ee250e5ec02f95889a157satok } 506562ab585f9e413d9696ee250e5ec02f95889a157satok 507562ab585f9e413d9696ee250e5ec02f95889a157satok @Override 508988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { 50900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 51000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 51100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 512da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 513da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "FinishSpellCheckerService"); 514da317ef68603dc7649f98bda495267973825e7fasatok } 515988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 5164c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok final ArrayList<SpellCheckerBindGroup> removeList = 5174c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok new ArrayList<SpellCheckerBindGroup>(); 518988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { 519988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (group == null) continue; 5204c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok // Use removeList to avoid modifying mSpellCheckerBindGroups in this loop. 5214c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok removeList.add(group); 5224c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok } 5234c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok final int removeSize = removeList.size(); 5244c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok for (int i = 0; i < removeSize; ++i) { 5254c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok removeList.get(i).removeListener(listener); 526988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 527988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 528988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 529988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 530df5659d3d317b5cf351baffe3e0d4876e89678bfsatok @Override 531ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok public void setCurrentSpellChecker(String locale, String sciId) { 53200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 53300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 53400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 535df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 536df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (mContext.checkCallingOrSelfPermission( 537df5659d3d317b5cf351baffe3e0d4876e89678bfsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 538df5659d3d317b5cf351baffe3e0d4876e89678bfsatok != PackageManager.PERMISSION_GRANTED) { 539df5659d3d317b5cf351baffe3e0d4876e89678bfsatok throw new SecurityException( 540df5659d3d317b5cf351baffe3e0d4876e89678bfsatok "Requires permission " 541df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 542df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 5435b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sciId); 544df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 545df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 546df5659d3d317b5cf351baffe3e0d4876e89678bfsatok 547ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok @Override 548ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok public void setCurrentSpellCheckerSubtype(String locale, int hashCode) { 54900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 55000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 55100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 552ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok synchronized(mSpellCheckerMap) { 553ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (mContext.checkCallingOrSelfPermission( 554ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok android.Manifest.permission.WRITE_SECURE_SETTINGS) 555ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok != PackageManager.PERMISSION_GRANTED) { 556ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok throw new SecurityException( 557ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok "Requires permission " 558ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 559ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 560a33c4fc5bed76727f1e06e522e0136101a2304cdsatok setCurrentSpellCheckerSubtypeLocked(hashCode); 561a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 562a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 563a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 564a33c4fc5bed76727f1e06e522e0136101a2304cdsatok @Override 565a33c4fc5bed76727f1e06e522e0136101a2304cdsatok public void setSpellCheckerEnabled(boolean enabled) { 56600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 56700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 56800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 569a33c4fc5bed76727f1e06e522e0136101a2304cdsatok synchronized(mSpellCheckerMap) { 570a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (mContext.checkCallingOrSelfPermission( 571a33c4fc5bed76727f1e06e522e0136101a2304cdsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 572a33c4fc5bed76727f1e06e522e0136101a2304cdsatok != PackageManager.PERMISSION_GRANTED) { 573a33c4fc5bed76727f1e06e522e0136101a2304cdsatok throw new SecurityException( 574a33c4fc5bed76727f1e06e522e0136101a2304cdsatok "Requires permission " 575a33c4fc5bed76727f1e06e522e0136101a2304cdsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 576a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 577a33c4fc5bed76727f1e06e522e0136101a2304cdsatok setSpellCheckerEnabledLocked(enabled); 578ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 579ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 580ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 5815b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok private void setCurrentSpellCheckerLocked(String sciId) { 582562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 5835b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok Slog.w(TAG, "setCurrentSpellChecker: " + sciId); 584562ab585f9e413d9696ee250e5ec02f95889a157satok } 5855b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || !mSpellCheckerMap.containsKey(sciId)) return; 586f39daef102f2dff7517e257eb25c2e3677247e83satok final SpellCheckerInfo currentSci = getCurrentSpellChecker(null); 587f39daef102f2dff7517e257eb25c2e3677247e83satok if (currentSci != null && currentSci.getId().equals(sciId)) { 588f39daef102f2dff7517e257eb25c2e3677247e83satok // Do nothing if the current spell checker is same as new spell checker. 589f39daef102f2dff7517e257eb25c2e3677247e83satok return; 590f39daef102f2dff7517e257eb25c2e3677247e83satok } 591df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final long ident = Binder.clearCallingIdentity(); 592df5659d3d317b5cf351baffe3e0d4876e89678bfsatok try { 59300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.putSelectedSpellChecker(sciId); 594f39daef102f2dff7517e257eb25c2e3677247e83satok setCurrentSpellCheckerSubtypeLocked(0); 595ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } finally { 596ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Binder.restoreCallingIdentity(ident); 597ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 598ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 599ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 600a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private void setCurrentSpellCheckerSubtypeLocked(int hashCode) { 601ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (DBG) { 602ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Slog.w(TAG, "setCurrentSpellCheckerSubtype: " + hashCode); 603ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 604ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerInfo sci = getCurrentSpellChecker(null); 605fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok int tempHashCode = 0; 606fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok for (int i = 0; sci != null && i < sci.getSubtypeCount(); ++i) { 607ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if(sci.getSubtypeAt(i).hashCode() == hashCode) { 608fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok tempHashCode = hashCode; 609ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok break; 610ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 611ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 612ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final long ident = Binder.clearCallingIdentity(); 613ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok try { 61400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.putSelectedSpellCheckerSubtype(tempHashCode); 615df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } finally { 616df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Binder.restoreCallingIdentity(ident); 617df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 618988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 619988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 620a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private void setSpellCheckerEnabledLocked(boolean enabled) { 621a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 622a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "setSpellCheckerEnabled: " + enabled); 623a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 624a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final long ident = Binder.clearCallingIdentity(); 625a33c4fc5bed76727f1e06e522e0136101a2304cdsatok try { 62600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.setSpellCheckerEnabled(enabled); 627a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } finally { 628a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Binder.restoreCallingIdentity(ident); 629a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 630a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 631a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 632a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private boolean isSpellCheckerEnabledLocked() { 633a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final long ident = Binder.clearCallingIdentity(); 634a33c4fc5bed76727f1e06e522e0136101a2304cdsatok try { 63500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final boolean retval = mSettings.isSpellCheckerEnabled(); 636a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 637a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "getSpellCheckerEnabled: " + retval); 638a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 639a33c4fc5bed76727f1e06e522e0136101a2304cdsatok return retval; 640a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } finally { 641a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Binder.restoreCallingIdentity(ident); 642a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 643a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 644a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 64571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn @Override 64671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 64771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 64871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn != PackageManager.PERMISSION_GRANTED) { 64971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 65071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println("Permission Denial: can't dump TextServicesManagerService from from pid=" 65171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn + Binder.getCallingPid() 65271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn + ", uid=" + Binder.getCallingUid()); 65371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn return; 65471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 65571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 65671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn synchronized(mSpellCheckerMap) { 65771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println("Current Text Services Manager state:"); 65871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(" Spell Checker Map:"); 65971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (Map.Entry<String, SpellCheckerInfo> ent : mSpellCheckerMap.entrySet()) { 66071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print(ent.getKey()); pw.println(":"); 66171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerInfo info = ent.getValue(); 66271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("id="); pw.println(info.getId()); 66371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("comp="); 66471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(info.getComponent().toShortString()); 66571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn int NS = info.getSubtypeCount(); 66671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (int i=0; i<NS; i++) { 66771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerSubtype st = info.getSubtypeAt(i); 66871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("Subtype #"); pw.print(i); pw.println(":"); 66971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("locale="); pw.println(st.getLocale()); 67071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("extraValue="); 67171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(st.getExtraValue()); 67271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 67371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 67471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(""); 67571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(" Spell Checker Bind Groups:"); 67671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (Map.Entry<String, SpellCheckerBindGroup> ent 67771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn : mSpellCheckerBindGroups.entrySet()) { 67871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerBindGroup grp = ent.getValue(); 67971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print(ent.getKey()); pw.print(" "); 68071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(grp); pw.println(":"); 68171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mInternalConnection="); 68271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(grp.mInternalConnection); 68371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mSpellChecker="); 68471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(grp.mSpellChecker); 68571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mBound="); pw.print(grp.mBound); 68671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" mConnected="); pw.println(grp.mConnected); 68771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn int NL = grp.mListeners.size(); 68871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (int i=0; i<NL; i++) { 68971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn InternalDeathRecipient listener = grp.mListeners.get(i); 69071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("Listener #"); pw.print(i); pw.println(":"); 69171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mTsListener="); 69271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mTsListener); 69371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mScListener="); 69471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mScListener); 69571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mGroup="); 69671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mGroup); 69771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mScLocale="); 69871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(listener.mScLocale); 69971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" mUid="); pw.println(listener.mUid); 70071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 70171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 70271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 70371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 70471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 705988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // SpellCheckerBindGroup contains active text service session listeners. 706988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from 707988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // mSpellCheckerBindGroups 708988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class SpellCheckerBindGroup { 709df5659d3d317b5cf351baffe3e0d4876e89678bfsatok private final String TAG = SpellCheckerBindGroup.class.getSimpleName(); 7106be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private final InternalServiceConnection mInternalConnection; 7114e713f14419a37f385cf1509b011982bdcf67edcsatok private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners = 7124e713f14419a37f385cf1509b011982bdcf67edcsatok new CopyOnWriteArrayList<InternalDeathRecipient>(); 71371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn public boolean mBound; 7146be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public ISpellCheckerService mSpellChecker; 7156be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public boolean mConnected; 716988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 717988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerBindGroup(InternalServiceConnection connection, 718988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener listener, String locale, 7195357806980269d846a15c845a6fcc0384fb18860satok ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 720988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mInternalConnection = connection; 72171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mBound = true; 7226be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = false; 7235357806980269d846a15c845a6fcc0384fb18860satok addListener(listener, locale, scListener, uid, bundle); 724988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 725988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 726988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ISpellCheckerService spellChecker) { 727da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 728da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "onServiceConnected"); 729da317ef68603dc7649f98bda495267973825e7fasatok } 7304e713f14419a37f385cf1509b011982bdcf67edcsatok 7314e713f14419a37f385cf1509b011982bdcf67edcsatok for (InternalDeathRecipient listener : mListeners) { 7324e713f14419a37f385cf1509b011982bdcf67edcsatok try { 7334e713f14419a37f385cf1509b011982bdcf67edcsatok final ISpellCheckerSession session = spellChecker.getISpellCheckerSession( 7344e713f14419a37f385cf1509b011982bdcf67edcsatok listener.mScLocale, listener.mScListener, listener.mBundle); 7354e713f14419a37f385cf1509b011982bdcf67edcsatok synchronized(mSpellCheckerMap) { 7364e713f14419a37f385cf1509b011982bdcf67edcsatok if (mListeners.contains(listener)) { 7374e713f14419a37f385cf1509b011982bdcf67edcsatok listener.mTsListener.onServiceConnected(session); 7384e713f14419a37f385cf1509b011982bdcf67edcsatok } 739988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 7404e713f14419a37f385cf1509b011982bdcf67edcsatok } catch (RemoteException e) { 7414e713f14419a37f385cf1509b011982bdcf67edcsatok Slog.e(TAG, "Exception in getting the spell checker session." 7424e713f14419a37f385cf1509b011982bdcf67edcsatok + "Reconnect to the spellchecker. ", e); 7434e713f14419a37f385cf1509b011982bdcf67edcsatok removeAll(); 7444e713f14419a37f385cf1509b011982bdcf67edcsatok return; 745988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 7464e713f14419a37f385cf1509b011982bdcf67edcsatok } 7474e713f14419a37f385cf1509b011982bdcf67edcsatok synchronized(mSpellCheckerMap) { 7486be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellChecker = spellChecker; 7496be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = true; 750988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 751988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 752988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 7536be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener, 7545357806980269d846a15c845a6fcc0384fb18860satok String locale, ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 755da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 756da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "addListener: " + locale); 757da317ef68603dc7649f98bda495267973825e7fasatok } 7586be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok InternalDeathRecipient recipient = null; 759988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 760988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 761988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 762988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 763988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mListeners.get(i).hasSpellCheckerListener(scListener)) { 764988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do not add the lister if the group already contains this. 7656be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return null; 766988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 767988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 7686be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok recipient = new InternalDeathRecipient( 7695357806980269d846a15c845a6fcc0384fb18860satok this, tsListener, locale, scListener, uid, bundle); 770988323c57bd25a58f05dfa492d9b9c8ab62c5153satok scListener.asBinder().linkToDeath(recipient, 0); 771df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.add(recipient); 772988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch(RemoteException e) { 773988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do nothing 774988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 775988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 776988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 7776be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return recipient; 778988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 779988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 780988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void removeListener(ISpellCheckerSessionListener listener) { 781da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 782df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "remove listener: " + listener.hashCode()); 783da317ef68603dc7649f98bda495267973825e7fasatok } 784988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 785988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 786988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ArrayList<InternalDeathRecipient> removeList = 787988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new ArrayList<InternalDeathRecipient>(); 788988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 789988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final InternalDeathRecipient tempRecipient = mListeners.get(i); 790988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if(tempRecipient.hasSpellCheckerListener(listener)) { 791df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 792df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "found existing listener."); 793df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 794988323c57bd25a58f05dfa492d9b9c8ab62c5153satok removeList.add(tempRecipient); 795988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 796988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 797988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int removeSize = removeList.size(); 798988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < removeSize; ++i) { 799df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 800df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Remove " + removeList.get(i)); 801df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 8022520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final InternalDeathRecipient idr = removeList.get(i); 8032520ed8cc3436df023a4f0ce3f436977b8ab3a99satok idr.mScListener.asBinder().unlinkToDeath(idr, 0); 8042520ed8cc3436df023a4f0ce3f436977b8ab3a99satok mListeners.remove(idr); 805988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 806988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 807988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 808988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 809988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 8104c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok // cleanLocked may remove elements from mSpellCheckerBindGroups 811988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void cleanLocked() { 812da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 813da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "cleanLocked"); 814da317ef68603dc7649f98bda495267973825e7fasatok } 81571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn // If there are no more active listeners, clean up. Only do this 81671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn // once. 81771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (mBound && mListeners.isEmpty()) { 81871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mBound = false; 819c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok final String sciId = mInternalConnection.mSciId; 82071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerBindGroup cur = mSpellCheckerBindGroups.get(sciId); 82171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (cur == this) { 822c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok if (DBG) { 823c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok Slog.d(TAG, "Remove bind group."); 824c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok } 825c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok mSpellCheckerBindGroups.remove(sciId); 8266be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 827988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext.unbindService(mInternalConnection); 828988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 829988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 8306be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 8316be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public void removeAll() { 8326be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Remove the spell checker bind unexpectedly."); 833df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 8342520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final int size = mListeners.size(); 8352520ed8cc3436df023a4f0ce3f436977b8ab3a99satok for (int i = 0; i < size; ++i) { 8362520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final InternalDeathRecipient idr = mListeners.get(i); 8372520ed8cc3436df023a4f0ce3f436977b8ab3a99satok idr.mScListener.asBinder().unlinkToDeath(idr, 0); 8382520ed8cc3436df023a4f0ce3f436977b8ab3a99satok } 839df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.clear(); 840df5659d3d317b5cf351baffe3e0d4876e89678bfsatok cleanLocked(); 841df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 8426be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 843988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 844988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 845988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalServiceConnection implements ServiceConnection { 846988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mSciId; 847988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mLocale; 8485357806980269d846a15c845a6fcc0384fb18860satok private final Bundle mBundle; 849988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalServiceConnection( 850060677f4686a93d92117d7d472e754423a368bdbsatok String id, String locale, Bundle bundle) { 851988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSciId = id; 852988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mLocale = locale; 8535357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 854988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 855988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 856988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 857988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ComponentName name, IBinder service) { 858988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 85900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka onServiceConnectedInnerLocked(name, service); 86000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 86100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 86200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 86300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private void onServiceConnectedInnerLocked(ComponentName name, IBinder service) { 86400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 86500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.w(TAG, "onServiceConnected: " + name); 86600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 86700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final ISpellCheckerService spellChecker = 86800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka ISpellCheckerService.Stub.asInterface(service); 86900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 87000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (group != null && this == group.mInternalConnection) { 87100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka group.onServiceConnected(spellChecker); 872988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 873988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 874988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 875988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 876988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceDisconnected(ComponentName name) { 87771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn synchronized(mSpellCheckerMap) { 87871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 8792cf1cf098513807ffd3420ae106f438e943d0cd8satok if (group != null && this == group.mInternalConnection) { 88071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mSpellCheckerBindGroups.remove(mSciId); 88171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 88271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 883988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 884988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 885988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 886988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalDeathRecipient implements IBinder.DeathRecipient { 887988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ITextServicesSessionListener mTsListener; 888988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ISpellCheckerSessionListener mScListener; 889988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final String mScLocale; 890988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerBindGroup mGroup; 891df5659d3d317b5cf351baffe3e0d4876e89678bfsatok public final int mUid; 8925357806980269d846a15c845a6fcc0384fb18860satok public final Bundle mBundle; 893988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalDeathRecipient(SpellCheckerBindGroup group, 894988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener tsListener, String scLocale, 8955357806980269d846a15c845a6fcc0384fb18860satok ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 896988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTsListener = tsListener; 897988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScListener = scListener; 898988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScLocale = scLocale; 899988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup = group; 900df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mUid = uid; 9015357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 902988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 903988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 904988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { 905df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return listener.asBinder().equals(mScListener.asBinder()); 906988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 907988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 908988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 909988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void binderDied() { 910988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup.removeListener(mScListener); 911988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 912988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 91300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 91400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private static class TextServicesSettings { 91500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private final ContentResolver mResolver; 91600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private int mCurrentUserId; 91700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public TextServicesSettings(ContentResolver resolver, int userId) { 91800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mResolver = resolver; 91900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mCurrentUserId = userId; 92000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 92100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 92200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void setCurrentUserId(int userId) { 92300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 92400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to " 92500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + userId + ", new ime = " + getSelectedSpellChecker()); 92600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 92700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TSMS settings are kept per user, so keep track of current user 92800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mCurrentUserId = userId; 92900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 93000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 93100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public int getCurrentUserId() { 93200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return mCurrentUserId; 93300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 93400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 93500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void putSelectedSpellChecker(String sciId) { 93600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.putStringForUser(mResolver, 93700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER, sciId, mCurrentUserId); 93800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 93900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 94000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void putSelectedSpellCheckerSubtype(int hashCode) { 94100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.putStringForUser(mResolver, 94200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode), 94300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mCurrentUserId); 94400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 94500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 94600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void setSpellCheckerEnabled(boolean enabled) { 94700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.putIntForUser(mResolver, 94800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0, mCurrentUserId); 94900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 95000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 95100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public String getSelectedSpellChecker() { 95200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return Settings.Secure.getStringForUser(mResolver, 95300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER, mCurrentUserId); 95400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 95500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 95600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public String getSelectedSpellCheckerSubtype() { 95700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return Settings.Secure.getStringForUser(mResolver, 95800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, mCurrentUserId); 95900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 96000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 96100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public boolean isSpellCheckerEnabled() { 96200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return Settings.Secure.getIntForUser(mResolver, 96300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SPELL_CHECKER_ENABLED, 1, mCurrentUserId) == 1; 96400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 96500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 96600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 96700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // ---------------------------------------------------------------------- 96800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // Utilities for debug 96900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private static String getStackTrace() { 97000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final StringBuilder sb = new StringBuilder(); 97100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 97200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka throw new RuntimeException(); 97300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RuntimeException e) { 97400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final StackTraceElement[] frames = e.getStackTrace(); 97500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // Start at 1 because the first frame is here and we don't care about it 97600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka for (int j = 1; j < frames.length; ++j) { 97700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka sb.append(frames[j].toString() + "\n"); 97800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 97900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 98000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return sb.toString(); 98100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 982988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 983