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 19095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawaimport com.android.internal.annotations.GuardedBy; 20988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.content.PackageMonitor; 21988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerService; 22988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSession; 23988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSessionListener; 24988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ITextServicesManager; 25988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ITextServicesSessionListener; 26988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 2703b2ea1102d9e3e9f189173878706ab04533eea3satokimport org.xmlpull.v1.XmlPullParserException; 2803b2ea1102d9e3e9f189173878706ab04533eea3satok 2900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.app.ActivityManagerNative; 3000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.app.AppGlobals; 3100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.app.IUserSwitchObserver; 32095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawaimport android.content.BroadcastReceiver; 33988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ComponentName; 3400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.content.ContentResolver; 35988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Context; 36988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Intent; 37095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawaimport android.content.IntentFilter; 38988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.ServiceConnection; 39095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawaimport android.content.pm.ApplicationInfo; 40988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.PackageManager; 41988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ResolveInfo; 42988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.pm.ServiceInfo; 43095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawaimport android.content.pm.UserInfo; 446be6d7548fb7c29a4d46dc985318ab2adf69f95fsatokimport android.os.Binder; 455357806980269d846a15c845a6fcc0384fb18860satokimport android.os.Bundle; 46988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.IBinder; 4700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.os.IRemoteCallback; 4800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.os.Process; 49988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.RemoteException; 5000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataokaimport android.os.UserHandle; 51095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawaimport android.os.UserManager; 52988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.provider.Settings; 53988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.service.textservice.SpellCheckerService; 545357806980269d846a15c845a6fcc0384fb18860satokimport android.text.TextUtils; 55988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.util.Slog; 5605f24700613fb4dce95fb6d5f8fe460d7a30c128satokimport android.view.inputmethod.InputMethodManager; 5705f24700613fb4dce95fb6d5f8fe460d7a30c128satokimport android.view.inputmethod.InputMethodSubtype; 58988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.SpellCheckerInfo; 59ada8c4e6a3da96a795f39a1028d448eb7aebfab3satokimport android.view.textservice.SpellCheckerSubtype; 60988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 6171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.io.FileDescriptor; 6203b2ea1102d9e3e9f189173878706ab04533eea3satokimport java.io.IOException; 6371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.io.PrintWriter; 64988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.ArrayList; 65988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.HashMap; 66988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.List; 6771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackbornimport java.util.Map; 684e713f14419a37f385cf1509b011982bdcf67edcsatokimport java.util.concurrent.CopyOnWriteArrayList; 69988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 70988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpublic class TextServicesManagerService extends ITextServicesManager.Stub { 71988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final String TAG = TextServicesManagerService.class.getSimpleName(); 72988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final boolean DBG = false; 73988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 74988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Context mContext; 75988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mSystemReady; 76988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final TextServicesMonitor mMonitor; 77988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = 78988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerInfo>(); 79988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>(); 80988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = 81988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new HashMap<String, SpellCheckerBindGroup>(); 8200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private final TextServicesSettings mSettings; 83988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 84a00271533f639c8ed36429c663889ac9f654bc72Svetoslav Ganov public void systemRunning() { 85988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 86988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = true; 87988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 88988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 89988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 90988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public TextServicesManagerService(Context context) { 91988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSystemReady = false; 92988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext = context; 93095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 94095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa final IntentFilter broadcastFilter = new IntentFilter(); 95095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa broadcastFilter.addAction(Intent.ACTION_USER_ADDED); 96095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa broadcastFilter.addAction(Intent.ACTION_USER_REMOVED); 97095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa mContext.registerReceiver(new TextServicesBroadcastReceiver(), broadcastFilter); 98095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 9900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka int userId = UserHandle.USER_OWNER; 10000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 10100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka ActivityManagerNative.getDefault().registerUserSwitchObserver( 10200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka new IUserSwitchObserver.Stub() { 10300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka @Override 10400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void onUserSwitching(int newUserId, IRemoteCallback reply) { 10500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka synchronized(mSpellCheckerMap) { 10600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka switchUserLocked(newUserId); 10700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 10800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (reply != null) { 10900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 11000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka reply.sendResult(null); 11100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RemoteException e) { 11200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 11300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 11400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 11500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 11600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka @Override 11700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void onUserSwitchComplete(int newUserId) throws RemoteException { 11800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 11900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka }); 12000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka userId = ActivityManagerNative.getDefault().getCurrentUser().id; 12100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RemoteException e) { 12200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e); 12300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 124988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mMonitor = new TextServicesMonitor(); 125d0d7503fd3e941113094532f28986f49b11b5fdbDianne Hackborn mMonitor.register(context, null, true); 12600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings = new TextServicesSettings(context.getContentResolver(), userId); 12700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 12800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // "switchUserLocked" initializes the states for the foreground user 12900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka switchUserLocked(userId); 13000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 13100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 13200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private void switchUserLocked(int userId) { 13300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.setCurrentUserId(userId); 134095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa updateCurrentProfileIds(); 13500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka unbindServiceLocked(); 13600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings); 137df5659d3d317b5cf351baffe3e0d4876e89678bfsatok SpellCheckerInfo sci = getCurrentSpellChecker(null); 138df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci == null) { 139df5659d3d317b5cf351baffe3e0d4876e89678bfsatok sci = findAvailSpellCheckerLocked(null, null); 140df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (sci != null) { 141df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // Set the current spell checker if there is one or more spell checkers 142df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // available. In this case, "sci" is the first one in the available spell 143df5659d3d317b5cf351baffe3e0d4876e89678bfsatok // checkers. 1445b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 145df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 146df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 147988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 148988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 149095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa void updateCurrentProfileIds() { 150095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa List<UserInfo> profiles = 151095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId()); 152095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null 153095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa for (int i = 0; i < currentProfileIds.length; i++) { 154095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa currentProfileIds[i] = profiles.get(i).id; 155095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 156095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa mSettings.setCurrentProfileIds(currentProfileIds); 157095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 158095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 159988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class TextServicesMonitor extends PackageMonitor { 16000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private boolean isChangingPackagesOfCurrentUser() { 16100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final int userId = getChangingUserId(); 16200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final boolean retval = userId == mSettings.getCurrentUserId(); 16300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 16400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- ignore this call back from a background user: " + userId); 16500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 16600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return retval; 16700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 16800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 169988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 170988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onSomePackagesChanged() { 17100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!isChangingPackagesOfCurrentUser()) { 17200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 17300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 174988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 17500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka buildSpellCheckerMapLocked( 17600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mContext, mSpellCheckerList, mSpellCheckerMap, mSettings); 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Update for each locale 178988323c57bd25a58f05dfa492d9b9c8ab62c5153satok SpellCheckerInfo sci = getCurrentSpellChecker(null); 17902260e2141fac0b6a712e4ca63702e657e8e7296Satoshi Kataoka // If no spell checker is enabled, just return. The user should explicitly 18002260e2141fac0b6a712e4ca63702e657e8e7296Satoshi Kataoka // enable the spell checker. 181da317ef68603dc7649f98bda495267973825e7fasatok if (sci == null) return; 182988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final String packageName = sci.getPackageName(); 183988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int change = isPackageDisappearing(packageName); 1845b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (// Package disappearing 1855b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE 1865b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok // Package modified 1875b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok || isPackageModified(packageName)) { 1885b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok sci = findAvailSpellCheckerLocked(null, packageName); 1895b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (sci != null) { 1905b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sci.getId()); 1915b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok } 192988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 193988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 194988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 195988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 196988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 197095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa class TextServicesBroadcastReceiver extends BroadcastReceiver { 198095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa @Override 199095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa public void onReceive(Context context, Intent intent) { 200095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa final String action = intent.getAction(); 201095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (Intent.ACTION_USER_ADDED.equals(action) 202095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa || Intent.ACTION_USER_REMOVED.equals(action)) { 203095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa updateCurrentProfileIds(); 204095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa return; 205095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 206095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa Slog.w(TAG, "Unexpected intent " + intent); 207095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 208095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 209095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 210988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static void buildSpellCheckerMapLocked(Context context, 21100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map, 21200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka TextServicesSettings settings) { 213988323c57bd25a58f05dfa492d9b9c8ab62c5153satok list.clear(); 214988323c57bd25a58f05dfa492d9b9c8ab62c5153satok map.clear(); 215988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final PackageManager pm = context.getPackageManager(); 21600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final List<ResolveInfo> services = pm.queryIntentServicesAsUser( 21700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA, 21800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka settings.getCurrentUserId()); 219988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int N = services.size(); 220988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < N; ++i) { 221988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ResolveInfo ri = services.get(i); 222988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ServiceInfo si = ri.serviceInfo; 223988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ComponentName compName = new ComponentName(si.packageName, si.name); 224988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) { 225988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "Skipping text service " + compName 226988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + ": it does not require the permission " 227988323c57bd25a58f05dfa492d9b9c8ab62c5153satok + android.Manifest.permission.BIND_TEXT_SERVICE); 228988323c57bd25a58f05dfa492d9b9c8ab62c5153satok continue; 229988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 230988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (DBG) Slog.d(TAG, "Add: " + compName); 23103b2ea1102d9e3e9f189173878706ab04533eea3satok try { 23203b2ea1102d9e3e9f189173878706ab04533eea3satok final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri); 2333cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok if (sci.getSubtypeCount() <= 0) { 2343cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok Slog.w(TAG, "Skipping text service " + compName 2353cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok + ": it does not contain subtypes."); 2363cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok continue; 2373cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok } 23803b2ea1102d9e3e9f189173878706ab04533eea3satok list.add(sci); 23903b2ea1102d9e3e9f189173878706ab04533eea3satok map.put(sci.getId(), sci); 24003b2ea1102d9e3e9f189173878706ab04533eea3satok } catch (XmlPullParserException e) { 24103b2ea1102d9e3e9f189173878706ab04533eea3satok Slog.w(TAG, "Unable to load the spell checker " + compName, e); 24203b2ea1102d9e3e9f189173878706ab04533eea3satok } catch (IOException e) { 24303b2ea1102d9e3e9f189173878706ab04533eea3satok Slog.w(TAG, "Unable to load the spell checker " + compName, e); 24403b2ea1102d9e3e9f189173878706ab04533eea3satok } 245988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 246da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 247da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "buildSpellCheckerMapLocked: " + list.size() + "," + map.size()); 248da317ef68603dc7649f98bda495267973825e7fasatok } 249988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 250988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 25100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // --------------------------------------------------------------------------------------- 25200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // Check whether or not this is a valid IPC. Assumes an IPC is valid when either 25300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // 1) it comes from the system process 25400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // 2) the calling process' user id is identical to the current user id TSMS thinks. 25500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private boolean calledFromValidUser() { 25600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final int uid = Binder.getCallingUid(); 25700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final int userId = UserHandle.getUserId(uid); 25800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 25900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? " 26000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID 26100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + " calling userId = " + userId + ", foreground user id = " 262095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid()); 26300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 26400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid); 26500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka for (int i = 0; i < packageNames.length; ++i) { 26600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 26700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- process name for "+ uid + " = " + packageNames[i]); 26800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 26900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 27000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RemoteException e) { 27100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 27200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 27300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 27400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) { 27500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return true; 27600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 277095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 278095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // Permits current profile to use TSFM as long as the current text service is the system's 279095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // one. This is a tentative solution and should be replaced with fully functional multiuser 280095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // support. 281095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // TODO: Implement multiuser support in TSMS. 282095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa final boolean isCurrentProfile = mSettings.isCurrentProfile(userId); 283095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (DBG) { 284095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa Slog.d(TAG, "--- userId = "+ userId + " isCurrentProfile = " + isCurrentProfile); 285095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 286095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (mSettings.isCurrentProfile(userId)) { 287095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa final SpellCheckerInfo spellCheckerInfo = getCurrentSpellCheckerWithoutVerification(); 288095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (spellCheckerInfo != null) { 289095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa final ServiceInfo serviceInfo = spellCheckerInfo.getServiceInfo(); 290095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa final boolean isSystemSpellChecker = 291095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa (serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 292095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (DBG) { 293095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa Slog.d(TAG, "--- current spell checker = "+ spellCheckerInfo.getPackageName() 294095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa + " isSystem = " + isSystemSpellChecker); 295095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 296095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (isSystemSpellChecker) { 297095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa return true; 298095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 299095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 300095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 301095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 302095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // Unlike InputMethodManagerService#calledFromValidUser, INTERACT_ACROSS_USERS_FULL isn't 303095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // taken into account here. Anyway this method is supposed to be removed once multiuser 304095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa // support is implemented. 305095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (DBG) { 306095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa Slog.d(TAG, "--- IPC from userId:" + userId + " is being ignored. \n" 307095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa + getStackTrace()); 308095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 309095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa return false; 31000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 31100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 31200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private boolean bindCurrentSpellCheckerService( 31300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Intent service, ServiceConnection conn, int flags) { 31400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (service == null || conn == null) { 31500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.e(TAG, "--- bind failed: service = " + service + ", conn = " + conn); 31600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return false; 31700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 31827b89e6658a0d233a53f5d7ca20dc57fec82d955Amith Yamasani return mContext.bindServiceAsUser(service, conn, flags, 31927b89e6658a0d233a53f5d7ca20dc57fec82d955Amith Yamasani new UserHandle(mSettings.getCurrentUserId())); 32000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 32100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 32200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private void unbindServiceLocked() { 32300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka for (SpellCheckerBindGroup scbg : mSpellCheckerBindGroups.values()) { 32400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka scbg.removeAll(); 32500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 32600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSpellCheckerBindGroups.clear(); 32700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 32800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 329988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: find an appropriate spell checker for specified locale 330988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) { 331988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int spellCheckersCount = mSpellCheckerList.size(); 332988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount == 0) { 333988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "no available spell checker services found"); 334988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return null; 335988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 336988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage != null) { 337988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < spellCheckersCount; ++i) { 338988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerInfo sci = mSpellCheckerList.get(i); 339988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (prefPackage.equals(sci.getPackageName())) { 340da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 341da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "findAvailSpellCheckerLocked: " + sci.getPackageName()); 342da317ef68603dc7649f98bda495267973825e7fasatok } 343988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return sci; 344988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 345988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 346988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 347988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (spellCheckersCount > 1) { 348988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.w(TAG, "more than one spell checker service found, picking first"); 349988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 350988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerList.get(0); 351988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 352988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 353988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Save SpellCheckerService by supported languages. Currently only one spell 354988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // checker is saved. 355988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 356988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerInfo getCurrentSpellChecker(String locale) { 35700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TODO: Make this work even for non-current users? 35800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 35900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return null; 36000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 361095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa return getCurrentSpellCheckerWithoutVerification(); 362095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 363095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 364095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa private SpellCheckerInfo getCurrentSpellCheckerWithoutVerification() { 365988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized (mSpellCheckerMap) { 36600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final String curSpellCheckerId = mSettings.getSelectedSpellChecker(); 367562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 368562ab585f9e413d9696ee250e5ec02f95889a157satok Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); 369562ab585f9e413d9696ee250e5ec02f95889a157satok } 370988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (TextUtils.isEmpty(curSpellCheckerId)) { 371df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return null; 372988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 373988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerMap.get(curSpellCheckerId); 374988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 375988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 376988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 3773cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok // TODO: Respect allowImplicitlySelectedSubtype 37817150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale". 379ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok @Override 3803cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok public SpellCheckerSubtype getCurrentSpellCheckerSubtype( 3813cb5b39a0e63d98c4e7b47e9a5b5758e9d4024bdsatok String locale, boolean allowImplicitlySelectedSubtype) { 38200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TODO: Make this work even for non-current users? 38300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 38400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return null; 38500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 386ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok synchronized (mSpellCheckerMap) { 38700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final String subtypeHashCodeStr = mSettings.getSelectedSpellCheckerSubtype(); 388ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (DBG) { 389c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr); 390ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 391ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerInfo sci = getCurrentSpellChecker(null); 392a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (sci == null || sci.getSubtypeCount() == 0) { 393a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 394a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "Subtype not found."); 395a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 396ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok return null; 397ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 398b387954a92eb6f15b7f49d5b946745f492a26363satok final int hashCode; 399b387954a92eb6f15b7f49d5b946745f492a26363satok if (!TextUtils.isEmpty(subtypeHashCodeStr)) { 400b387954a92eb6f15b7f49d5b946745f492a26363satok hashCode = Integer.valueOf(subtypeHashCodeStr); 401b387954a92eb6f15b7f49d5b946745f492a26363satok } else { 402b387954a92eb6f15b7f49d5b946745f492a26363satok hashCode = 0; 403ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 404b387954a92eb6f15b7f49d5b946745f492a26363satok if (hashCode == 0 && !allowImplicitlySelectedSubtype) { 405fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok return null; 406fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok } 40705f24700613fb4dce95fb6d5f8fe460d7a30c128satok String candidateLocale = null; 40805f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (hashCode == 0) { 40905f24700613fb4dce95fb6d5f8fe460d7a30c128satok // Spell checker language settings == "auto" 41005f24700613fb4dce95fb6d5f8fe460d7a30c128satok final InputMethodManager imm = 41105f24700613fb4dce95fb6d5f8fe460d7a30c128satok (InputMethodManager)mContext.getSystemService(Context.INPUT_METHOD_SERVICE); 41205f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (imm != null) { 41305f24700613fb4dce95fb6d5f8fe460d7a30c128satok final InputMethodSubtype currentInputMethodSubtype = 41405f24700613fb4dce95fb6d5f8fe460d7a30c128satok imm.getCurrentInputMethodSubtype(); 41505f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (currentInputMethodSubtype != null) { 41605f24700613fb4dce95fb6d5f8fe460d7a30c128satok final String localeString = currentInputMethodSubtype.getLocale(); 41705f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (!TextUtils.isEmpty(localeString)) { 41805f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 1. Use keyboard locale if available in the spell checker 41905f24700613fb4dce95fb6d5f8fe460d7a30c128satok candidateLocale = localeString; 42005f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 42105f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 42205f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 42305f24700613fb4dce95fb6d5f8fe460d7a30c128satok if (candidateLocale == null) { 42405f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 2. Use System locale if available in the spell checker 42505f24700613fb4dce95fb6d5f8fe460d7a30c128satok candidateLocale = mContext.getResources().getConfiguration().locale.toString(); 42605f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 42705f24700613fb4dce95fb6d5f8fe460d7a30c128satok } 428b387954a92eb6f15b7f49d5b946745f492a26363satok SpellCheckerSubtype candidate = null; 429ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok for (int i = 0; i < sci.getSubtypeCount(); ++i) { 430ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerSubtype scs = sci.getSubtypeAt(i); 431b387954a92eb6f15b7f49d5b946745f492a26363satok if (hashCode == 0) { 43217150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka final String scsLocale = scs.getLocale(); 43317150cf91be1478e367c2ef5e4f5baaa66b487d0Satoshi Kataoka if (candidateLocale.equals(scsLocale)) { 434b387954a92eb6f15b7f49d5b946745f492a26363satok return scs; 435b387954a92eb6f15b7f49d5b946745f492a26363satok } else if (candidate == null) { 4367018a90c323a7f0deb37939d5505ff112ac637f5satok if (candidateLocale.length() >= 2 && scsLocale.length() >= 2 4377018a90c323a7f0deb37939d5505ff112ac637f5satok && candidateLocale.startsWith(scsLocale)) { 43805f24700613fb4dce95fb6d5f8fe460d7a30c128satok // Fall back to the applicable language 439b387954a92eb6f15b7f49d5b946745f492a26363satok candidate = scs; 440b387954a92eb6f15b7f49d5b946745f492a26363satok } 441b387954a92eb6f15b7f49d5b946745f492a26363satok } 442b387954a92eb6f15b7f49d5b946745f492a26363satok } else if (scs.hashCode() == hashCode) { 443a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 44470deff4c107963164f8b88365909fd30ab5e6526satok Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale 44570deff4c107963164f8b88365909fd30ab5e6526satok + ", " + scs.getLocale()); 446a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 44705f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 3. Use the user specified spell check language 448ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok return scs; 449ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 450ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 45105f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 4. Fall back to the applicable language and return it if not null 45205f24700613fb4dce95fb6d5f8fe460d7a30c128satok // 5. Simply just return it even if it's null which means we could find no suitable 45305f24700613fb4dce95fb6d5f8fe460d7a30c128satok // spell check languages 454b387954a92eb6f15b7f49d5b946745f492a26363satok return candidate; 455ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 456ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 457ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 458988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 4595b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok public void getSpellCheckerService(String sciId, String locale, 4605357806980269d846a15c845a6fcc0384fb18860satok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 4615357806980269d846a15c845a6fcc0384fb18860satok Bundle bundle) { 46200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 46300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 46400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 465988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSystemReady) { 466988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 467988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4685b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) { 469988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Slog.e(TAG, "getSpellCheckerService: Invalid input."); 470988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 471988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 472988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 473988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (!mSpellCheckerMap.containsKey(sciId)) { 474988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 475988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4765b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok final SpellCheckerInfo sci = mSpellCheckerMap.get(sciId); 477df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final int uid = Binder.getCallingUid(); 478988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mSpellCheckerBindGroups.containsKey(sciId)) { 4796be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId); 4806be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup != null) { 4816be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalDeathRecipient recipient = 4826be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.get(sciId).addListener( 4835357806980269d846a15c845a6fcc0384fb18860satok tsListener, locale, scListener, uid, bundle); 4846be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (recipient == null) { 4856be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 4866be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "Didn't create a death recipient."); 4876be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4886be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 4896be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4906be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (bindGroup.mSpellChecker == null & bindGroup.mConnected) { 4916be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "The state of the spell checker bind group is illegal."); 4926be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 4936be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } else if (bindGroup.mSpellChecker != null) { 4946be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 495df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind found. Return a spell checker session now. " 496df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + "Listeners count = " + bindGroup.mListeners.size()); 4976be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 4986be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 4996be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final ISpellCheckerSession session = 5006be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.mSpellChecker.getISpellCheckerSession( 5015357806980269d846a15c845a6fcc0384fb18860satok recipient.mScLocale, recipient.mScListener, bundle); 502df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (session != null) { 503df5659d3d317b5cf351baffe3e0d4876e89678bfsatok tsListener.onServiceConnected(session); 504df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return; 505df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } else { 506df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 507df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Existing bind already expired. "); 508df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 509df5659d3d317b5cf351baffe3e0d4876e89678bfsatok bindGroup.removeAll(); 510df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 5116be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } catch (RemoteException e) { 5126be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Exception in getting spell checker session: " + e); 5136be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok bindGroup.removeAll(); 5146be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 5156be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 5166be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 517988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 5186be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final long ident = Binder.clearCallingIdentity(); 5196be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok try { 5205357806980269d846a15c845a6fcc0384fb18860satok startSpellCheckerServiceInnerLocked( 5215357806980269d846a15c845a6fcc0384fb18860satok sci, locale, tsListener, scListener, uid, bundle); 5226be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } finally { 5236be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Binder.restoreCallingIdentity(ident); 524988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 525988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 526988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return; 527988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 528988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 529a33c4fc5bed76727f1e06e522e0136101a2304cdsatok @Override 530a33c4fc5bed76727f1e06e522e0136101a2304cdsatok public boolean isSpellCheckerEnabled() { 53100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 53200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return false; 53300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 534a33c4fc5bed76727f1e06e522e0136101a2304cdsatok synchronized(mSpellCheckerMap) { 535a33c4fc5bed76727f1e06e522e0136101a2304cdsatok return isSpellCheckerEnabledLocked(); 536a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 537a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 538a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 5396be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale, 540df5659d3d317b5cf351baffe3e0d4876e89678bfsatok ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, 5415357806980269d846a15c845a6fcc0384fb18860satok int uid, Bundle bundle) { 542df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 543df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Start spell checker session inner locked."); 544df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 5456be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final String sciId = info.getId(); 5466be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final InternalServiceConnection connection = new InternalServiceConnection( 547060677f4686a93d92117d7d472e754423a368bdbsatok sciId, locale, bundle); 5486be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); 5496be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok serviceIntent.setComponent(info.getComponent()); 5506be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 5516be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.w(TAG, "bind service: " + info.getId()); 5526be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 55300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!bindCurrentSpellCheckerService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { 5546be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Failed to get a spell checker service."); 5556be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return; 5566be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 5576be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok final SpellCheckerBindGroup group = new SpellCheckerBindGroup( 5585357806980269d846a15c845a6fcc0384fb18860satok connection, tsListener, locale, scListener, uid, bundle); 5596be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellCheckerBindGroups.put(sciId, group); 5606be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 5616be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 562988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 563562ab585f9e413d9696ee250e5ec02f95889a157satok public SpellCheckerInfo[] getEnabledSpellCheckers() { 56400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TODO: Make this work even for non-current users? 56500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 56600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return null; 56700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 568da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 569da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "getEnabledSpellCheckers: " + mSpellCheckerList.size()); 570da317ef68603dc7649f98bda495267973825e7fasatok for (int i = 0; i < mSpellCheckerList.size(); ++i) { 571da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "EnabledSpellCheckers: " + mSpellCheckerList.get(i).getPackageName()); 572da317ef68603dc7649f98bda495267973825e7fasatok } 573da317ef68603dc7649f98bda495267973825e7fasatok } 574562ab585f9e413d9696ee250e5ec02f95889a157satok return mSpellCheckerList.toArray(new SpellCheckerInfo[mSpellCheckerList.size()]); 575562ab585f9e413d9696ee250e5ec02f95889a157satok } 576562ab585f9e413d9696ee250e5ec02f95889a157satok 577562ab585f9e413d9696ee250e5ec02f95889a157satok @Override 578988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { 57900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 58000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 58100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 582da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 583da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "FinishSpellCheckerService"); 584da317ef68603dc7649f98bda495267973825e7fasatok } 585988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 5864c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok final ArrayList<SpellCheckerBindGroup> removeList = 5874c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok new ArrayList<SpellCheckerBindGroup>(); 588988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { 589988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (group == null) continue; 5904c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok // Use removeList to avoid modifying mSpellCheckerBindGroups in this loop. 5914c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok removeList.add(group); 5924c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok } 5934c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok final int removeSize = removeList.size(); 5944c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok for (int i = 0; i < removeSize; ++i) { 5954c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok removeList.get(i).removeListener(listener); 596988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 597988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 598988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 599988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 600df5659d3d317b5cf351baffe3e0d4876e89678bfsatok @Override 601ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok public void setCurrentSpellChecker(String locale, String sciId) { 60200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 60300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 60400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 605df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 606df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (mContext.checkCallingOrSelfPermission( 607df5659d3d317b5cf351baffe3e0d4876e89678bfsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 608df5659d3d317b5cf351baffe3e0d4876e89678bfsatok != PackageManager.PERMISSION_GRANTED) { 609df5659d3d317b5cf351baffe3e0d4876e89678bfsatok throw new SecurityException( 610df5659d3d317b5cf351baffe3e0d4876e89678bfsatok "Requires permission " 611df5659d3d317b5cf351baffe3e0d4876e89678bfsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 612df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 6135b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok setCurrentSpellCheckerLocked(sciId); 614df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 615df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 616df5659d3d317b5cf351baffe3e0d4876e89678bfsatok 617ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok @Override 618ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok public void setCurrentSpellCheckerSubtype(String locale, int hashCode) { 61900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 62000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 62100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 622ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok synchronized(mSpellCheckerMap) { 623ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (mContext.checkCallingOrSelfPermission( 624ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok android.Manifest.permission.WRITE_SECURE_SETTINGS) 625ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok != PackageManager.PERMISSION_GRANTED) { 626ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok throw new SecurityException( 627ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok "Requires permission " 628ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 629ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 630a33c4fc5bed76727f1e06e522e0136101a2304cdsatok setCurrentSpellCheckerSubtypeLocked(hashCode); 631a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 632a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 633a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 634a33c4fc5bed76727f1e06e522e0136101a2304cdsatok @Override 635a33c4fc5bed76727f1e06e522e0136101a2304cdsatok public void setSpellCheckerEnabled(boolean enabled) { 63600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (!calledFromValidUser()) { 63700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return; 63800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 639a33c4fc5bed76727f1e06e522e0136101a2304cdsatok synchronized(mSpellCheckerMap) { 640a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (mContext.checkCallingOrSelfPermission( 641a33c4fc5bed76727f1e06e522e0136101a2304cdsatok android.Manifest.permission.WRITE_SECURE_SETTINGS) 642a33c4fc5bed76727f1e06e522e0136101a2304cdsatok != PackageManager.PERMISSION_GRANTED) { 643a33c4fc5bed76727f1e06e522e0136101a2304cdsatok throw new SecurityException( 644a33c4fc5bed76727f1e06e522e0136101a2304cdsatok "Requires permission " 645a33c4fc5bed76727f1e06e522e0136101a2304cdsatok + android.Manifest.permission.WRITE_SECURE_SETTINGS); 646a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 647a33c4fc5bed76727f1e06e522e0136101a2304cdsatok setSpellCheckerEnabledLocked(enabled); 648ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 649ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 650ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 6515b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok private void setCurrentSpellCheckerLocked(String sciId) { 652562ab585f9e413d9696ee250e5ec02f95889a157satok if (DBG) { 6535b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok Slog.w(TAG, "setCurrentSpellChecker: " + sciId); 654562ab585f9e413d9696ee250e5ec02f95889a157satok } 6555b9b5a9553a0276dc6b7f1f458c8d4ed03227988satok if (TextUtils.isEmpty(sciId) || !mSpellCheckerMap.containsKey(sciId)) return; 656f39daef102f2dff7517e257eb25c2e3677247e83satok final SpellCheckerInfo currentSci = getCurrentSpellChecker(null); 657f39daef102f2dff7517e257eb25c2e3677247e83satok if (currentSci != null && currentSci.getId().equals(sciId)) { 658f39daef102f2dff7517e257eb25c2e3677247e83satok // Do nothing if the current spell checker is same as new spell checker. 659f39daef102f2dff7517e257eb25c2e3677247e83satok return; 660f39daef102f2dff7517e257eb25c2e3677247e83satok } 661df5659d3d317b5cf351baffe3e0d4876e89678bfsatok final long ident = Binder.clearCallingIdentity(); 662df5659d3d317b5cf351baffe3e0d4876e89678bfsatok try { 66300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.putSelectedSpellChecker(sciId); 664f39daef102f2dff7517e257eb25c2e3677247e83satok setCurrentSpellCheckerSubtypeLocked(0); 665ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } finally { 666ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Binder.restoreCallingIdentity(ident); 667ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 668ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 669ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok 670a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private void setCurrentSpellCheckerSubtypeLocked(int hashCode) { 671ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if (DBG) { 672ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok Slog.w(TAG, "setCurrentSpellCheckerSubtype: " + hashCode); 673ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 674ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final SpellCheckerInfo sci = getCurrentSpellChecker(null); 675fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok int tempHashCode = 0; 676fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok for (int i = 0; sci != null && i < sci.getSubtypeCount(); ++i) { 677ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok if(sci.getSubtypeAt(i).hashCode() == hashCode) { 678fbedf1a3978d5dfc4a886e4c7107d4bc1923f740satok tempHashCode = hashCode; 679ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok break; 680ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 681ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok } 682ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok final long ident = Binder.clearCallingIdentity(); 683ada8c4e6a3da96a795f39a1028d448eb7aebfab3satok try { 68400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.putSelectedSpellCheckerSubtype(tempHashCode); 685df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } finally { 686df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Binder.restoreCallingIdentity(ident); 687df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 688988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 689988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 690a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private void setSpellCheckerEnabledLocked(boolean enabled) { 691a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 692a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "setSpellCheckerEnabled: " + enabled); 693a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 694a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final long ident = Binder.clearCallingIdentity(); 695a33c4fc5bed76727f1e06e522e0136101a2304cdsatok try { 69600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mSettings.setSpellCheckerEnabled(enabled); 697a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } finally { 698a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Binder.restoreCallingIdentity(ident); 699a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 700a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 701a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 702a33c4fc5bed76727f1e06e522e0136101a2304cdsatok private boolean isSpellCheckerEnabledLocked() { 703a33c4fc5bed76727f1e06e522e0136101a2304cdsatok final long ident = Binder.clearCallingIdentity(); 704a33c4fc5bed76727f1e06e522e0136101a2304cdsatok try { 70500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final boolean retval = mSettings.isSpellCheckerEnabled(); 706a33c4fc5bed76727f1e06e522e0136101a2304cdsatok if (DBG) { 707a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Slog.w(TAG, "getSpellCheckerEnabled: " + retval); 708a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 709a33c4fc5bed76727f1e06e522e0136101a2304cdsatok return retval; 710a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } finally { 711a33c4fc5bed76727f1e06e522e0136101a2304cdsatok Binder.restoreCallingIdentity(ident); 712a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 713a33c4fc5bed76727f1e06e522e0136101a2304cdsatok } 714a33c4fc5bed76727f1e06e522e0136101a2304cdsatok 71571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn @Override 71671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 71771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 71871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn != PackageManager.PERMISSION_GRANTED) { 71971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 72071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println("Permission Denial: can't dump TextServicesManagerService from from pid=" 72171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn + Binder.getCallingPid() 72271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn + ", uid=" + Binder.getCallingUid()); 72371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn return; 72471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 72571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 72671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn synchronized(mSpellCheckerMap) { 72771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println("Current Text Services Manager state:"); 72871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(" Spell Checker Map:"); 72971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (Map.Entry<String, SpellCheckerInfo> ent : mSpellCheckerMap.entrySet()) { 73071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print(ent.getKey()); pw.println(":"); 73171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerInfo info = ent.getValue(); 73271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("id="); pw.println(info.getId()); 73371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("comp="); 73471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(info.getComponent().toShortString()); 73571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn int NS = info.getSubtypeCount(); 73671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (int i=0; i<NS; i++) { 73771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerSubtype st = info.getSubtypeAt(i); 73871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("Subtype #"); pw.print(i); pw.println(":"); 73971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("locale="); pw.println(st.getLocale()); 74071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("extraValue="); 74171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(st.getExtraValue()); 74271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 74371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 74471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(""); 74571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(" Spell Checker Bind Groups:"); 74671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (Map.Entry<String, SpellCheckerBindGroup> ent 74771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn : mSpellCheckerBindGroups.entrySet()) { 74871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerBindGroup grp = ent.getValue(); 74971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print(ent.getKey()); pw.print(" "); 75071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(grp); pw.println(":"); 75171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mInternalConnection="); 75271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(grp.mInternalConnection); 75371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mSpellChecker="); 75471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(grp.mSpellChecker); 75571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mBound="); pw.print(grp.mBound); 75671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" mConnected="); pw.println(grp.mConnected); 75771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn int NL = grp.mListeners.size(); 75871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn for (int i=0; i<NL; i++) { 75971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn InternalDeathRecipient listener = grp.mListeners.get(i); 76071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("Listener #"); pw.print(i); pw.println(":"); 76171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mTsListener="); 76271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mTsListener); 76371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mScListener="); 76471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mScListener); 76571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mGroup="); 76671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.println(listener.mGroup); 76771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" "); pw.print("mScLocale="); 76871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(listener.mScLocale); 76971e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn pw.print(" mUid="); pw.println(listener.mUid); 77071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 77171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 77271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 77371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 77471e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn 775988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // SpellCheckerBindGroup contains active text service session listeners. 776988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from 777988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // mSpellCheckerBindGroups 778988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class SpellCheckerBindGroup { 779df5659d3d317b5cf351baffe3e0d4876e89678bfsatok private final String TAG = SpellCheckerBindGroup.class.getSimpleName(); 7806be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private final InternalServiceConnection mInternalConnection; 7814e713f14419a37f385cf1509b011982bdcf67edcsatok private final CopyOnWriteArrayList<InternalDeathRecipient> mListeners = 7824e713f14419a37f385cf1509b011982bdcf67edcsatok new CopyOnWriteArrayList<InternalDeathRecipient>(); 78371e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn public boolean mBound; 7846be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public ISpellCheckerService mSpellChecker; 7856be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public boolean mConnected; 786988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 787988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerBindGroup(InternalServiceConnection connection, 788988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener listener, String locale, 7895357806980269d846a15c845a6fcc0384fb18860satok ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 790988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mInternalConnection = connection; 79171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mBound = true; 7926be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = false; 7935357806980269d846a15c845a6fcc0384fb18860satok addListener(listener, locale, scListener, uid, bundle); 794988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 795988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 796988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ISpellCheckerService spellChecker) { 797da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 798da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "onServiceConnected"); 799da317ef68603dc7649f98bda495267973825e7fasatok } 8004e713f14419a37f385cf1509b011982bdcf67edcsatok 8014e713f14419a37f385cf1509b011982bdcf67edcsatok for (InternalDeathRecipient listener : mListeners) { 8024e713f14419a37f385cf1509b011982bdcf67edcsatok try { 8034e713f14419a37f385cf1509b011982bdcf67edcsatok final ISpellCheckerSession session = spellChecker.getISpellCheckerSession( 8044e713f14419a37f385cf1509b011982bdcf67edcsatok listener.mScLocale, listener.mScListener, listener.mBundle); 8054e713f14419a37f385cf1509b011982bdcf67edcsatok synchronized(mSpellCheckerMap) { 8064e713f14419a37f385cf1509b011982bdcf67edcsatok if (mListeners.contains(listener)) { 8074e713f14419a37f385cf1509b011982bdcf67edcsatok listener.mTsListener.onServiceConnected(session); 8084e713f14419a37f385cf1509b011982bdcf67edcsatok } 809988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 8104e713f14419a37f385cf1509b011982bdcf67edcsatok } catch (RemoteException e) { 8114e713f14419a37f385cf1509b011982bdcf67edcsatok Slog.e(TAG, "Exception in getting the spell checker session." 8124e713f14419a37f385cf1509b011982bdcf67edcsatok + "Reconnect to the spellchecker. ", e); 8134e713f14419a37f385cf1509b011982bdcf67edcsatok removeAll(); 8144e713f14419a37f385cf1509b011982bdcf67edcsatok return; 815988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 8164e713f14419a37f385cf1509b011982bdcf67edcsatok } 8174e713f14419a37f385cf1509b011982bdcf67edcsatok synchronized(mSpellCheckerMap) { 8186be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mSpellChecker = spellChecker; 8196be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok mConnected = true; 820988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 821988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 822988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 8236be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener, 8245357806980269d846a15c845a6fcc0384fb18860satok String locale, ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 825da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 826da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "addListener: " + locale); 827da317ef68603dc7649f98bda495267973825e7fasatok } 8286be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok InternalDeathRecipient recipient = null; 829988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 830988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 831988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 832988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 833988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mListeners.get(i).hasSpellCheckerListener(scListener)) { 834988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do not add the lister if the group already contains this. 8356be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return null; 836988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 837988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 8386be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok recipient = new InternalDeathRecipient( 8395357806980269d846a15c845a6fcc0384fb18860satok this, tsListener, locale, scListener, uid, bundle); 840988323c57bd25a58f05dfa492d9b9c8ab62c5153satok scListener.asBinder().linkToDeath(recipient, 0); 841df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.add(recipient); 842988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch(RemoteException e) { 843988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do nothing 844988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 845988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 846988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 8476be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok return recipient; 848988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 849988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 850988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void removeListener(ISpellCheckerSessionListener listener) { 851da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 852df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "remove listener: " + listener.hashCode()); 853da317ef68603dc7649f98bda495267973825e7fasatok } 854988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 855988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int size = mListeners.size(); 856988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final ArrayList<InternalDeathRecipient> removeList = 857988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new ArrayList<InternalDeathRecipient>(); 858988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < size; ++i) { 859988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final InternalDeathRecipient tempRecipient = mListeners.get(i); 860988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if(tempRecipient.hasSpellCheckerListener(listener)) { 861df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 862df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "found existing listener."); 863df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 864988323c57bd25a58f05dfa492d9b9c8ab62c5153satok removeList.add(tempRecipient); 865988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 866988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 867988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final int removeSize = removeList.size(); 868988323c57bd25a58f05dfa492d9b9c8ab62c5153satok for (int i = 0; i < removeSize; ++i) { 869df5659d3d317b5cf351baffe3e0d4876e89678bfsatok if (DBG) { 870df5659d3d317b5cf351baffe3e0d4876e89678bfsatok Slog.w(TAG, "Remove " + removeList.get(i)); 871df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 8722520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final InternalDeathRecipient idr = removeList.get(i); 8732520ed8cc3436df023a4f0ce3f436977b8ab3a99satok idr.mScListener.asBinder().unlinkToDeath(idr, 0); 8742520ed8cc3436df023a4f0ce3f436977b8ab3a99satok mListeners.remove(idr); 875988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 876988323c57bd25a58f05dfa492d9b9c8ab62c5153satok cleanLocked(); 877988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 878988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 879988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 8804c3fa642ef1c0e1bb3303d4b25d8af4e6a7d08a2satok // cleanLocked may remove elements from mSpellCheckerBindGroups 881988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void cleanLocked() { 882da317ef68603dc7649f98bda495267973825e7fasatok if (DBG) { 883da317ef68603dc7649f98bda495267973825e7fasatok Slog.d(TAG, "cleanLocked"); 884da317ef68603dc7649f98bda495267973825e7fasatok } 88571e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn // If there are no more active listeners, clean up. Only do this 88671e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn // once. 88771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (mBound && mListeners.isEmpty()) { 88871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mBound = false; 889c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok final String sciId = mInternalConnection.mSciId; 89071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn SpellCheckerBindGroup cur = mSpellCheckerBindGroups.get(sciId); 89171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn if (cur == this) { 892c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok if (DBG) { 893c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok Slog.d(TAG, "Remove bind group."); 894c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok } 895c7b60f72dda5c5f222342a9d60435ec353a8a19bsatok mSpellCheckerBindGroups.remove(sciId); 8966be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 897988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mContext.unbindService(mInternalConnection); 898988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 899988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 9006be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok 9016be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok public void removeAll() { 9026be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Slog.e(TAG, "Remove the spell checker bind unexpectedly."); 903df5659d3d317b5cf351baffe3e0d4876e89678bfsatok synchronized(mSpellCheckerMap) { 9042520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final int size = mListeners.size(); 9052520ed8cc3436df023a4f0ce3f436977b8ab3a99satok for (int i = 0; i < size; ++i) { 9062520ed8cc3436df023a4f0ce3f436977b8ab3a99satok final InternalDeathRecipient idr = mListeners.get(i); 9072520ed8cc3436df023a4f0ce3f436977b8ab3a99satok idr.mScListener.asBinder().unlinkToDeath(idr, 0); 9082520ed8cc3436df023a4f0ce3f436977b8ab3a99satok } 909df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mListeners.clear(); 910df5659d3d317b5cf351baffe3e0d4876e89678bfsatok cleanLocked(); 911df5659d3d317b5cf351baffe3e0d4876e89678bfsatok } 9126be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 913988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 914988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 915988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalServiceConnection implements ServiceConnection { 916988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mSciId; 917988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final String mLocale; 9185357806980269d846a15c845a6fcc0384fb18860satok private final Bundle mBundle; 919988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalServiceConnection( 920060677f4686a93d92117d7d472e754423a368bdbsatok String id, String locale, Bundle bundle) { 921988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSciId = id; 922988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mLocale = locale; 9235357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 924988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 925988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 926988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 927988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ComponentName name, IBinder service) { 928988323c57bd25a58f05dfa492d9b9c8ab62c5153satok synchronized(mSpellCheckerMap) { 92900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka onServiceConnectedInnerLocked(name, service); 93000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 93100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 93200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 93300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private void onServiceConnectedInnerLocked(ComponentName name, IBinder service) { 93400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 93500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.w(TAG, "onServiceConnected: " + name); 93600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 93700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final ISpellCheckerService spellChecker = 93800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka ISpellCheckerService.Stub.asInterface(service); 93900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 94000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (group != null && this == group.mInternalConnection) { 94100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka group.onServiceConnected(spellChecker); 942988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 943988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 944988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 945988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 946988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceDisconnected(ComponentName name) { 94771e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn synchronized(mSpellCheckerMap) { 94871e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); 9492cf1cf098513807ffd3420ae106f438e943d0cd8satok if (group != null && this == group.mInternalConnection) { 95071e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn mSpellCheckerBindGroups.remove(mSciId); 95171e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 95271e14da93c8fea512fedf1b5226d28cd2c330238Dianne Hackborn } 953988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 954988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 955988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 956988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private class InternalDeathRecipient implements IBinder.DeathRecipient { 957988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ITextServicesSessionListener mTsListener; 958988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final ISpellCheckerSessionListener mScListener; 959988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final String mScLocale; 960988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerBindGroup mGroup; 961df5659d3d317b5cf351baffe3e0d4876e89678bfsatok public final int mUid; 9625357806980269d846a15c845a6fcc0384fb18860satok public final Bundle mBundle; 963988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public InternalDeathRecipient(SpellCheckerBindGroup group, 964988323c57bd25a58f05dfa492d9b9c8ab62c5153satok ITextServicesSessionListener tsListener, String scLocale, 9655357806980269d846a15c845a6fcc0384fb18860satok ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { 966988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTsListener = tsListener; 967988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScListener = scListener; 968988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mScLocale = scLocale; 969988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup = group; 970df5659d3d317b5cf351baffe3e0d4876e89678bfsatok mUid = uid; 9715357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 972988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 973988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 974988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { 975df5659d3d317b5cf351baffe3e0d4876e89678bfsatok return listener.asBinder().equals(mScListener.asBinder()); 976988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 977988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 978988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 979988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void binderDied() { 980988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mGroup.removeListener(mScListener); 981988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 982988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 98300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 98400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private static class TextServicesSettings { 98500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private final ContentResolver mResolver; 98600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private int mCurrentUserId; 987095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa @GuardedBy("mLock") 988095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa private int[] mCurrentProfileIds = new int[0]; 989095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa private Object mLock = new Object(); 990095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 99100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public TextServicesSettings(ContentResolver resolver, int userId) { 99200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mResolver = resolver; 99300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mCurrentUserId = userId; 99400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 99500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 99600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void setCurrentUserId(int userId) { 99700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka if (DBG) { 99800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to " 99900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka + userId + ", new ime = " + getSelectedSpellChecker()); 100000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 100100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // TSMS settings are kept per user, so keep track of current user 100200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mCurrentUserId = userId; 100300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 100400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 1005095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa public void setCurrentProfileIds(int[] currentProfileIds) { 1006095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa synchronized (mLock) { 1007095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa mCurrentProfileIds = currentProfileIds; 1008095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 1009095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 1010095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 1011095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa public boolean isCurrentProfile(int userId) { 1012095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa synchronized (mLock) { 1013095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (userId == mCurrentUserId) return true; 1014095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa for (int i = 0; i < mCurrentProfileIds.length; i++) { 1015095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa if (userId == mCurrentProfileIds[i]) return true; 1016095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 1017095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa return false; 1018095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 1019095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa } 1020095fa371643b1d8e829067ea4ed93c357b39e773Yohei Yukawa 102100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public int getCurrentUserId() { 102200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return mCurrentUserId; 102300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 102400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 102500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void putSelectedSpellChecker(String sciId) { 102600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.putStringForUser(mResolver, 102700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER, sciId, mCurrentUserId); 102800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 102900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 103000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void putSelectedSpellCheckerSubtype(int hashCode) { 103100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.putStringForUser(mResolver, 103200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode), 103300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka mCurrentUserId); 103400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 103500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 103600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public void setSpellCheckerEnabled(boolean enabled) { 103700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.putIntForUser(mResolver, 103800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0, mCurrentUserId); 103900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 104000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 104100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public String getSelectedSpellChecker() { 104200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return Settings.Secure.getStringForUser(mResolver, 104300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER, mCurrentUserId); 104400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 104500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 104600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public String getSelectedSpellCheckerSubtype() { 104700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return Settings.Secure.getStringForUser(mResolver, 104800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, mCurrentUserId); 104900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 105000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 105100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka public boolean isSpellCheckerEnabled() { 105200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return Settings.Secure.getIntForUser(mResolver, 105300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka Settings.Secure.SPELL_CHECKER_ENABLED, 1, mCurrentUserId) == 1; 105400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 105500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 105600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka 105700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // ---------------------------------------------------------------------- 105800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // Utilities for debug 105900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka private static String getStackTrace() { 106000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final StringBuilder sb = new StringBuilder(); 106100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka try { 106200d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka throw new RuntimeException(); 106300d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } catch (RuntimeException e) { 106400d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka final StackTraceElement[] frames = e.getStackTrace(); 106500d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka // Start at 1 because the first frame is here and we don't care about it 106600d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka for (int j = 1; j < frames.length; ++j) { 106700d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka sb.append(frames[j].toString() + "\n"); 106800d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 106900d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 107000d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka return sb.toString(); 107100d2d4125e4944ebcabdecd423573ee00f716293Satoshi Kataoka } 1072988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 1073