summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java158
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java57
2 files changed, 186 insertions, 29 deletions
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d45869e07586..840c6e48a190 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1674,40 +1674,93 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public List<InputMethodInfo> getInputMethodList() {
- return getInputMethodList(false /* isVrOnly */);
+ final int callingUserId = UserHandle.getCallingUserId();
+ synchronized (mMethodMap) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
+ return Collections.emptyList();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getInputMethodListLocked(false /* isVrOnly */, resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
@Override
public List<InputMethodInfo> getVrInputMethodList() {
- return getInputMethodList(true /* isVrOnly */);
- }
-
- private List<InputMethodInfo> getInputMethodList(final boolean isVrOnly) {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (mMethodMap) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUserLocked()) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
return Collections.emptyList();
}
- ArrayList<InputMethodInfo> methodList = new ArrayList<>();
- for (InputMethodInfo info : mMethodList) {
-
- if (info.isVrOnly() == isVrOnly) {
- methodList.add(info);
- }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getInputMethodListLocked(true /* isVrOnly */, resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- return methodList;
}
}
@Override
public List<InputMethodInfo> getEnabledInputMethodList() {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (mMethodMap) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUserLocked()) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
return Collections.emptyList();
}
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getEnabledInputMethodListLocked(resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @GuardedBy("mMethodMap")
+ private List<InputMethodInfo> getInputMethodListLocked(boolean isVrOnly,
+ @UserIdInt int userId) {
+ final ArrayList<InputMethodInfo> methodList;
+ if (userId == mSettings.getCurrentUserId()) {
+ // Create a copy.
+ methodList = new ArrayList<>(mMethodList);
+ } else {
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ methodList = new ArrayList<>();
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ new ArrayMap<>();
+ AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+ queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+ methodList);
+ }
+ methodList.removeIf(imi -> imi.isVrOnly() != isVrOnly);
+ return methodList;
+ }
+
+ @GuardedBy("mMethodMap")
+ private List<InputMethodInfo> getEnabledInputMethodListLocked(@UserIdInt int userId) {
+ if (userId == mSettings.getCurrentUserId()) {
return mSettings.getEnabledInputMethodListLocked();
}
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ new ArrayMap<>();
+ AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+ queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+ methodList);
+ final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+ mContext.getContentResolver(), methodMap, methodList, userId, true);
+ return settings.getEnabledInputMethodListLocked();
}
/**
@@ -1717,11 +1770,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
boolean allowsImplicitlySelectedSubtypes) {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (mMethodMap) {
- // TODO: Make this work even for non-current users?
- if (!calledFromValidUserLocked()) {
+ final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+ mSettings.getCurrentUserId(), null);
+ if (resolvedUserIds.length != 1) {
return Collections.emptyList();
}
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getEnabledInputMethodSubtypeListLocked(imiId,
+ allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @GuardedBy("mMethodMap")
+ private List<InputMethodSubtype> getEnabledInputMethodSubtypeListLocked(String imiId,
+ boolean allowsImplicitlySelectedSubtypes, @UserIdInt int userId) {
+ if (userId == mSettings.getCurrentUserId()) {
final InputMethodInfo imi;
if (imiId == null && mCurMethodId != null) {
imi = mMethodMap.get(mCurMethodId);
@@ -1734,6 +1803,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mSettings.getEnabledInputMethodSubtypeListLocked(
mContext, imi, allowsImplicitlySelectedSubtypes);
}
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ new ArrayMap<>();
+ AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+ queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap,
+ methodList);
+ final InputMethodInfo imi = methodMap.get(imiId);
+ if (imi == null) {
+ return Collections.emptyList();
+ }
+ final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+ mContext.getContentResolver(), methodMap, methodList, userId, true);
+ return settings.getEnabledInputMethodSubtypeListLocked(
+ mContext, imi, allowsImplicitlySelectedSubtypes);
}
/**
@@ -4545,6 +4629,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private int handleShellCommandListInputMethods(@NonNull ShellCommand shellCommand) {
boolean all = false;
boolean brief = false;
+ int userIdToBeResolved = UserHandle.USER_CURRENT;
while (true) {
final String nextOption = shellCommand.getNextOption();
if (nextOption == null) {
@@ -4557,19 +4642,34 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
case "-s":
brief = true;
break;
+ case "-u":
+ case "--user":
+ userIdToBeResolved = UserHandle.parseUserArg(shellCommand.getNextArgRequired());
+ break;
}
}
- final List<InputMethodInfo> methods = all ?
- getInputMethodList() : getEnabledInputMethodList();
- final PrintWriter pr = shellCommand.getOutPrintWriter();
- final Printer printer = x -> pr.println(x);
- final int N = methods.size();
- for (int i = 0; i < N; ++i) {
- if (brief) {
- pr.println(methods.get(i).getId());
- } else {
- pr.print(methods.get(i).getId()); pr.println(":");
- methods.get(i).dump(printer, " ");
+ synchronized (mMethodMap) {
+ final PrintWriter pr = shellCommand.getOutPrintWriter();
+ final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+ mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+ for (int userId : userIds) {
+ final List<InputMethodInfo> methods = all
+ ? getInputMethodListLocked(false, userId)
+ : getEnabledInputMethodListLocked(userId);
+ if (userIds.length > 1) {
+ pr.print("User #");
+ pr.print(userId);
+ pr.println(":");
+ }
+ for (InputMethodInfo info : methods) {
+ if (brief) {
+ pr.println(info.getId());
+ } else {
+ pr.print(info.getId());
+ pr.println(":");
+ info.dump(pr::println, " ");
+ }
+ }
}
}
return ShellCommandResult.SUCCESS;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 1137bf967d24..2f7687148e2e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -29,9 +29,12 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
import android.util.Slog;
@@ -42,8 +45,10 @@ import android.view.textservice.SpellCheckerInfo;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.StartInputFlags;
+import com.android.server.LocalServices;
import com.android.server.textservices.TextServicesManagerInternal;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
@@ -1286,4 +1291,56 @@ final class InputMethodUtils {
return true;
}
+ /**
+ * Converts a user ID, which can be a pseudo user ID such as {@link UserHandle#USER_ALL} to a
+ * list of real user IDs.
+ *
+ * <p>Currently this method also converts profile user ID to profile parent user ID.</p>
+ *
+ * @param userIdToBeResolved A user ID. Two pseudo user ID {@link UserHandle#USER_CURRENT} and
+ * {@link UserHandle#USER_ALL} are also supported
+ * @param currentUserId A real user ID, which will be used when {@link UserHandle#USER_CURRENT}
+ * is specified in {@code userIdToBeResolved}.
+ * @param warningWriter A {@link PrintWriter} to output some debug messages. {@code null} if
+ * no debug message is required.
+ * @return An integer array that contain user IDs.
+ */
+ static int[] resolveUserId(@UserIdInt int userIdToBeResolved,
+ @UserIdInt int currentUserId, @Nullable PrintWriter warningWriter) {
+ final UserManagerInternal userManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+
+ if (userIdToBeResolved == UserHandle.USER_ALL) {
+ final IntArray result = new IntArray();
+ for (int userId : userManagerInternal.getUserIds()) {
+ final int parentUserId = userManagerInternal.getProfileParentId(userId);
+ if (result.indexOf(parentUserId) < 0) {
+ result.add(parentUserId);
+ }
+ }
+ return result.toArray();
+ }
+
+ final int sourceUserId;
+ if (userIdToBeResolved == UserHandle.USER_CURRENT) {
+ sourceUserId = currentUserId;
+ } else if (userIdToBeResolved < 0) {
+ if (warningWriter != null) {
+ warningWriter.print("Pseudo user ID ");
+ warningWriter.print(userIdToBeResolved);
+ warningWriter.println(" is not supported.");
+ }
+ return new int[]{};
+ } else if (userManagerInternal.exists(userIdToBeResolved)) {
+ sourceUserId = userIdToBeResolved;
+ } else {
+ if (warningWriter != null) {
+ warningWriter.print("User #");
+ warningWriter.print(userIdToBeResolved);
+ warningWriter.println(" does not exit.");
+ }
+ return new int[]{};
+ }
+ return new int[]{userManagerInternal.getProfileParentId(sourceUserId)};
+ }
}