Enable background users to call IMM#getCurrentInputMethodSubtype()

This is a follow up CL to my previous CLs [1][2], which let query APIs
defined in InputMethodManager support background users.

With this CL,

  InputMethodManager#getCurrentInputMethodSubtype()

is also fully supported under multi-user / multi-profile environment.

 [1]: I192a0f5a1375170d17a4c08af94f23966dbaea8b
      7f8ee4b9dd
 [2]: I48f57dc7184e85bdb422fd9d1d56e60381654125
      e960986554

Bug: 34886274
Bug: 122164939
Bug: 237316307
Test: atest CtsInputMethodTestCases:InputMethodSubtypeTest
Change-Id: Icb09f9cb1a4147884faa9952b2e03ec4afa9f0b1
This commit is contained in:
Yohei Yukawa
2022-07-28 09:04:20 +09:00
parent 2cc1eee4a7
commit a6a2072452
5 changed files with 82 additions and 9 deletions

View File

@@ -182,9 +182,9 @@ final class IInputMethodManagerInvoker {
@AnyThread
@Nullable
InputMethodSubtype getCurrentInputMethodSubtype() {
InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) {
try {
return mTarget.getCurrentInputMethodSubtype();
return mTarget.getCurrentInputMethodSubtype(userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -3374,7 +3374,7 @@ public final class InputMethodManager {
*/
@Nullable
public InputMethodSubtype getCurrentInputMethodSubtype() {
return mServiceInvoker.getCurrentInputMethodSubtype();
return mServiceInvoker.getCurrentInputMethodSubtype(UserHandle.myUserId());
}
/**

View File

@@ -88,7 +88,10 @@ interface IInputMethodManager {
+ "android.Manifest.permission.TEST_INPUT_METHOD)")
boolean isInputMethodPickerShownForTest();
@nullable InputMethodSubtype getCurrentInputMethodSubtype();
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ "android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)")
@nullable InputMethodSubtype getCurrentInputMethodSubtype(int userId);
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.

View File

@@ -5284,18 +5284,38 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
/**
* Gets the current subtype of this input method.
*
* @param userId User ID to be queried about.
* @return The current {@link InputMethodSubtype} for the specified user.
*/
@Nullable
@Override
public InputMethodSubtype getCurrentInputMethodSubtype() {
public InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) {
if (UserHandle.getCallingUserId() != userId) {
mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
}
synchronized (ImfLock.class) {
// TODO: Make this work even for non-current users?
if (!calledFromValidUserLocked()) {
return null;
if (mSettings.getCurrentUserId() == userId) {
return getCurrentInputMethodSubtypeLocked();
}
return getCurrentInputMethodSubtypeLocked();
final ArrayMap<String, InputMethodInfo> methodMap = queryMethodMapForUser(userId);
final InputMethodSettings settings = new InputMethodSettings(mContext, methodMap,
userId, false);
return settings.getCurrentInputMethodSubtypeForNonCurrentUsers();
}
}
/**
* Returns the current {@link InputMethodSubtype} for the current user.
*
* <p>CAVEATS: You must also update
* {@link InputMethodSettings#getCurrentInputMethodSubtypeForNonCurrentUsers()}
* when you update the algorithm of this method.</p>
*
* <p>TODO: Address code duplication between this and
* {@link InputMethodSettings#getCurrentInputMethodSubtypeForNonCurrentUsers()}.</p>
*/
@GuardedBy("ImfLock.class")
InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
String selectedMethodId = getSelectedMethodIdLocked();

View File

@@ -818,6 +818,56 @@ final class InputMethodUtils {
}
}
/**
* A variant of {@link InputMethodManagerService#getCurrentInputMethodSubtypeLocked()} for
* non-current users.
*
* <p>TODO: Address code duplication between this and
* {@link InputMethodManagerService#getCurrentInputMethodSubtypeLocked()}.</p>
*
* @return {@link InputMethodSubtype} if exists. {@code null} otherwise.
*/
@Nullable
InputMethodSubtype getCurrentInputMethodSubtypeForNonCurrentUsers() {
final String selectedMethodId = getSelectedInputMethod();
if (selectedMethodId == null) {
return null;
}
final InputMethodInfo imi = mMethodMap.get(selectedMethodId);
if (imi == null || imi.getSubtypeCount() == 0) {
return null;
}
final int subtypeHashCode = getSelectedInputMethodSubtypeHashCode();
if (subtypeHashCode != InputMethodUtils.NOT_A_SUBTYPE_ID) {
final int subtypeIndex = SubtypeUtils.getSubtypeIdFromHashCode(imi,
subtypeHashCode);
if (subtypeIndex >= 0) {
return imi.getSubtypeAt(subtypeIndex);
}
}
// If there are no selected subtypes, the framework will try to find the most applicable
// subtype from explicitly or implicitly enabled subtypes.
final List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypes =
getEnabledInputMethodSubtypeListLocked(imi, true);
// If there is only one explicitly or implicitly enabled subtype, just returns it.
if (explicitlyOrImplicitlyEnabledSubtypes.isEmpty()) {
return null;
}
if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
return explicitlyOrImplicitlyEnabledSubtypes.get(0);
}
final InputMethodSubtype subtype = SubtypeUtils.findLastResortApplicableSubtypeLocked(
mRes, explicitlyOrImplicitlyEnabledSubtypes, SubtypeUtils.SUBTYPE_MODE_KEYBOARD,
null, true);
if (subtype != null) {
return subtype;
}
return SubtypeUtils.findLastResortApplicableSubtypeLocked(mRes,
explicitlyOrImplicitlyEnabledSubtypes, null, null, true);
}
public void dumpLocked(final Printer pw, final String prefix) {
pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds));