diff options
5 files changed, 88 insertions, 42 deletions
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 3adafd725a10..2dc225af6482 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -439,10 +439,11 @@ final class SystemServiceRegistry { }}); registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class, - new StaticServiceFetcher<TextServicesManager>() { + new CachedServiceFetcher<TextServicesManager>() { @Override - public TextServicesManager createService() { - return TextServicesManager.getInstance(); + public TextServicesManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + return TextServicesManager.createInstance(ctx); }}); registerService(Context.KEYGUARD_SERVICE, KeyguardManager.class, diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index 9733701ee0f0..f553ca512881 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -27,7 +27,6 @@ import android.util.Log; import com.android.internal.textservice.ISpellCheckerSession; import com.android.internal.textservice.ISpellCheckerSessionListener; -import com.android.internal.textservice.ITextServicesManager; import com.android.internal.textservice.ITextServicesSessionListener; import dalvik.system.CloseGuard; @@ -96,7 +95,7 @@ public class SpellCheckerSession { private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2; private final InternalListener mInternalListener; - private final ITextServicesManager mTextServicesManager; + private final TextServicesManager mTextServicesManager; private final SpellCheckerInfo mSpellCheckerInfo; @UnsupportedAppUsage private final SpellCheckerSessionListener mSpellCheckerSessionListener; @@ -124,7 +123,7 @@ public class SpellCheckerSession { * @hide */ public SpellCheckerSession( - SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener) { + SpellCheckerInfo info, TextServicesManager tsm, SpellCheckerSessionListener listener) { if (info == null || listener == null || tsm == null) { throw new NullPointerException(); } @@ -166,12 +165,8 @@ public class SpellCheckerSession { */ public void close() { mGuard.close(); - try { - mSpellCheckerSessionListenerImpl.close(); - mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl); - } catch (RemoteException e) { - // do nothing - } + mSpellCheckerSessionListenerImpl.close(); + mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl); } /** diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java index 5dc8b19444b0..9ff64d9b268a 100644 --- a/core/java/android/view/textservice/TextServicesManager.java +++ b/core/java/android/view/textservice/TextServicesManager.java @@ -16,16 +16,20 @@ package android.view.textservice; +import android.annotation.NonNull; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; +import android.annotation.UserIdInt; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.os.UserHandle; import android.util.Log; import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener; +import com.android.internal.textservice.ISpellCheckerSessionListener; import com.android.internal.textservice.ITextServicesManager; import java.util.Locale; @@ -67,17 +71,41 @@ public final class TextServicesManager { private static final String TAG = TextServicesManager.class.getSimpleName(); private static final boolean DBG = false; + /** + * @deprecated Do not use. Just kept because of {@link UnsupportedAppUsage} in + * {@link #getInstance()}. + */ + @Deprecated private static TextServicesManager sInstance; private final ITextServicesManager mService; - private TextServicesManager() throws ServiceNotFoundException { + @UserIdInt + private final int mUserId; + + private TextServicesManager(@UserIdInt int userId) throws ServiceNotFoundException { mService = ITextServicesManager.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TEXT_SERVICES_MANAGER_SERVICE)); + mUserId = userId; + } + + /** + * The factory method of {@link TextServicesManager}. + * + * @param context {@link Context} from which {@link TextServicesManager} should be instantiated. + * @return {@link TextServicesManager} that is associated with {@link Context#getUserId()}. + * @throws ServiceNotFoundException When {@link TextServicesManager} is not available. + * @hide + */ + @NonNull + public static TextServicesManager createInstance(@NonNull Context context) + throws ServiceNotFoundException { + return new TextServicesManager(context.getUserId()); } /** - * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist. + * @deprecated Do not use. Just kept because of {@link UnsupportedAppUsage} in + * {@link #getInstance()}. * @hide */ @UnsupportedAppUsage @@ -85,7 +113,7 @@ public final class TextServicesManager { synchronized (TextServicesManager.class) { if (sInstance == null) { try { - sInstance = new TextServicesManager(); + sInstance = new TextServicesManager(UserHandle.myUserId()); } catch (ServiceNotFoundException e) { throw new IllegalStateException(e); } @@ -136,7 +164,7 @@ public final class TextServicesManager { final SpellCheckerInfo sci; try { - sci = mService.getCurrentSpellChecker(null); + sci = mService.getCurrentSpellChecker(mUserId, null); } catch (RemoteException e) { return null; } @@ -174,9 +202,9 @@ public final class TextServicesManager { if (subtypeInUse == null) { return null; } - final SpellCheckerSession session = new SpellCheckerSession(sci, mService, listener); + final SpellCheckerSession session = new SpellCheckerSession(sci, this, listener); try { - mService.getSpellCheckerService(sci.getId(), subtypeInUse.getLocale(), + mService.getSpellCheckerService(mUserId, sci.getId(), subtypeInUse.getLocale(), session.getTextServicesSessionListener(), session.getSpellCheckerSessionListener(), bundle); } catch (RemoteException e) { @@ -191,7 +219,7 @@ public final class TextServicesManager { @UnsupportedAppUsage public SpellCheckerInfo[] getEnabledSpellCheckers() { try { - final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(); + final SpellCheckerInfo[] retval = mService.getEnabledSpellCheckers(mUserId); if (DBG) { Log.d(TAG, "getEnabledSpellCheckers: " + (retval != null ? retval.length : "null")); } @@ -208,7 +236,7 @@ public final class TextServicesManager { public SpellCheckerInfo getCurrentSpellChecker() { try { // Passing null as a locale for ICS - return mService.getCurrentSpellChecker(null); + return mService.getCurrentSpellChecker(mUserId, null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -221,7 +249,7 @@ public final class TextServicesManager { public SpellCheckerSubtype getCurrentSpellCheckerSubtype( boolean allowImplicitlySelectedSubtype) { try { - return mService.getCurrentSpellCheckerSubtype(allowImplicitlySelectedSubtype); + return mService.getCurrentSpellCheckerSubtype(mUserId, allowImplicitlySelectedSubtype); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -233,7 +261,15 @@ public final class TextServicesManager { @UnsupportedAppUsage public boolean isSpellCheckerEnabled() { try { - return mService.isSpellCheckerEnabled(); + return mService.isSpellCheckerEnabled(mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + void finishSpellCheckerService(ISpellCheckerSessionListener listener) { + try { + mService.finishSpellCheckerService(mUserId, listener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl index 20f2aa06cf1e..8022949d1728 100644 --- a/core/java/com/android/internal/textservice/ITextServicesManager.aidl +++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl @@ -29,12 +29,13 @@ import android.view.textservice.SpellCheckerSubtype; * @hide */ interface ITextServicesManager { - SpellCheckerInfo getCurrentSpellChecker(String locale); - SpellCheckerSubtype getCurrentSpellCheckerSubtype(boolean allowImplicitlySelectedSubtype); - oneway void getSpellCheckerService(String sciId, in String locale, + SpellCheckerInfo getCurrentSpellChecker(int userId, String locale); + SpellCheckerSubtype getCurrentSpellCheckerSubtype(int userId, + boolean allowImplicitlySelectedSubtype); + oneway void getSpellCheckerService(int userId, String sciId, in String locale, in ITextServicesSessionListener tsListener, in ISpellCheckerSessionListener scListener, in Bundle bundle); - oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener); - boolean isSpellCheckerEnabled(); - SpellCheckerInfo[] getEnabledSpellCheckers(); + oneway void finishSpellCheckerService(int userId, in ISpellCheckerSessionListener listener); + boolean isSpellCheckerEnabled(int userId); + SpellCheckerInfo[] getEnabledSpellCheckers(int userId); } diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java index 7236d79c55ab..d4aa59d3ce85 100644 --- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java +++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java @@ -16,6 +16,8 @@ package com.android.server.textservices; +import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -513,8 +515,8 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { // TODO: Save SpellCheckerService by supported languages. Currently only one spell // checker is saved. @Override - public SpellCheckerInfo getCurrentSpellChecker(String locale) { - int userId = UserHandle.getCallingUserId(); + public SpellCheckerInfo getCurrentSpellChecker(@UserIdInt int userId, String locale) { + verifyUser(userId); synchronized (mLock) { final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); if (tsd == null) return null; @@ -527,11 +529,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { // TODO: Save SpellCheckerSubtype by supported languages by looking at "locale". @Override public SpellCheckerSubtype getCurrentSpellCheckerSubtype( - boolean allowImplicitlySelectedSubtype) { + @UserIdInt int userId, boolean allowImplicitlySelectedSubtype) { + verifyUser(userId); + final int subtypeHashCode; final SpellCheckerInfo sci; final Locale systemLocale; - final int userId = UserHandle.getCallingUserId(); synchronized (mLock) { final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); @@ -591,17 +594,17 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } @Override - public void getSpellCheckerService(String sciId, String locale, + public void getSpellCheckerService(@UserIdInt int userId, String sciId, String locale, ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, Bundle bundle) { + verifyUser(userId); if (TextUtils.isEmpty(sciId) || tsListener == null || scListener == null) { Slog.e(TAG, "getSpellCheckerService: Invalid input."); return; } - int callingUserId = UserHandle.getCallingUserId(); synchronized (mLock) { - final TextServicesData tsd = getDataFromCallingUserIdLocked(callingUserId); + final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); if (tsd == null) return; HashMap<String, SpellCheckerInfo> spellCheckerMap = tsd.mSpellCheckerMap; @@ -634,8 +637,8 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } @Override - public boolean isSpellCheckerEnabled() { - int userId = UserHandle.getCallingUserId(); + public boolean isSpellCheckerEnabled(@UserIdInt int userId) { + verifyUser(userId); synchronized (mLock) { final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); @@ -671,11 +674,11 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } @Override - public SpellCheckerInfo[] getEnabledSpellCheckers() { - int callingUserId = UserHandle.getCallingUserId(); + public SpellCheckerInfo[] getEnabledSpellCheckers(@UserIdInt int userId) { + verifyUser(userId); synchronized (mLock) { - final TextServicesData tsd = getDataFromCallingUserIdLocked(callingUserId); + final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); if (tsd == null) return null; ArrayList<SpellCheckerInfo> spellCheckerList = tsd.mSpellCheckerList; @@ -691,11 +694,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } @Override - public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { + public void finishSpellCheckerService(@UserIdInt int userId, + ISpellCheckerSessionListener listener) { if (DBG) { Slog.d(TAG, "FinishSpellCheckerService"); } - int userId = UserHandle.getCallingUserId(); + verifyUser(userId); synchronized (mLock) { final TextServicesData tsd = getDataFromCallingUserIdLocked(userId); @@ -716,6 +720,15 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } } + private void verifyUser(@UserIdInt int userId) { + final int callingUserId = UserHandle.getCallingUserId(); + if (userId != callingUserId) { + mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, + "Cross-user interaction requires INTERACT_ACROSS_USERS_FULL. userId=" + userId + + " callingUserId=" + callingUserId); + } + } + private void setCurrentSpellCheckerLocked(@Nullable SpellCheckerInfo sci, TextServicesData tsd) { final String sciId = (sci != null) ? sci.getId() : ""; if (DBG) { |