From 04a226334d4f2d6296d2837fa4ae165ef98e10e9 Mon Sep 17 00:00:00 2001 From: Wilson Wu Date: Tue, 14 Dec 2021 18:29:56 +0800 Subject: [PATCH] Add getInputMethodList API for locked user state When work profile disable by quick settings, the user would be locked then we cannot query installed input method lists for work user by existings API InputMethodManager#getInputMethodListAsUser(). Adding a new API to query input method services regardless of the user state. This API currently only used by Settings, it shouldn't affect the original behavior for other usages. Bug: 210083408 Test: verify we can get input methods list after disable work apps by quick settings Test: atest CtsInputMethodTestCases Change-Id: I54d5dbec7e76d6a68935007ed3af0641f717a7c5 --- .../view/inputmethod/InputMethodManager.java | 21 ++++++ .../inputmethod/DirectBootAwareness.java | 47 ++++++++++++++ .../internal/view/IInputMethodManager.aidl | 1 + .../InputMethodSettingValuesWrapper.java | 4 +- .../InputMethodManagerService.java | 64 +++++++++++++------ 5 files changed, 118 insertions(+), 19 deletions(-) create mode 100644 core/java/com/android/internal/inputmethod/DirectBootAwareness.java diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 7566ceab334d5..0bb3cc21c9052 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -86,6 +86,7 @@ import android.view.WindowManager.LayoutParams.SoftInputModeFlags; import android.view.autofill.AutofillManager; import com.android.internal.annotations.GuardedBy; +import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.InputMethodDebug; @@ -1233,6 +1234,26 @@ public final class InputMethodManager { } } + /** + * Returns the list of installed input methods for the specified user. + * + * @param userId user ID to query + * @param directBootAwareness {@code true} if caller want to query installed input methods list + * on user locked state. + * @return {@link List} of {@link InputMethodInfo}. + * @hide + */ + @RequiresPermission(INTERACT_ACROSS_USERS_FULL) + @NonNull + public List getInputMethodListAsUser(@UserIdInt int userId, + @DirectBootAwareness int directBootAwareness) { + try { + return mService.getAwareLockedInputMethodList(userId, directBootAwareness); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Returns the list of enabled input methods. * diff --git a/core/java/com/android/internal/inputmethod/DirectBootAwareness.java b/core/java/com/android/internal/inputmethod/DirectBootAwareness.java new file mode 100644 index 0000000000000..51f914f737e96 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/DirectBootAwareness.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.inputmethod; + + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; + +import java.lang.annotation.Retention; + +/** + * Specifies the decided filtering mode regarding IMEs' DirectBoot awareness when querying IMEs. + */ +@Retention(SOURCE) +@IntDef({DirectBootAwareness.AUTO, DirectBootAwareness.ANY}) +public @interface DirectBootAwareness { + /** + * The same semantics as {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO}, that + * is, if the user to be queried is still locked, then only DirectBoot-aware IMEs will be + * matched. If the user to be queried is already unlocked, then IMEs will not be filtered out + * based on their DirectBoot awareness. + */ + int AUTO = 0; + /** + * The same semantics as specifying both + * {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE} and + * {@link android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE}, that is, IME will never + * be filtered out based on their DirectBoot awareness, no matter whether the user to be queried + * is still locked or already unlocked. + */ + int ANY = 1; +} diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 350ec33326bd7..2dc7c42c95a9b 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -35,6 +35,7 @@ interface IInputMethodManager { // TODO: Use ParceledListSlice instead List getInputMethodList(int userId); + List getAwareLockedInputMethodList(int userId, int directBootAwareness); // TODO: Use ParceledListSlice instead List getEnabledInputMethodList(int userId); List getEnabledInputMethodSubtypeList(in String imiId, diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java index 39e6dcecba312..5860bdabe764a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSettingValuesWrapper.java @@ -27,6 +27,7 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.GuardedBy; +import com.android.internal.inputmethod.DirectBootAwareness; import java.util.ArrayList; import java.util.HashMap; @@ -88,7 +89,8 @@ public class InputMethodSettingValuesWrapper { public void refreshAllInputMethodAndSubtypes() { mMethodList.clear(); - mMethodList.addAll(mImm.getInputMethodListAsUser(mContentResolver.getUserId())); + mMethodList.addAll(mImm.getInputMethodListAsUser( + mContentResolver.getUserId(), DirectBootAwareness.ANY)); } public List getInputMethodList() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index da3729d7498f5..2c635cbc57d95 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -149,6 +149,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.compat.IPlatformCompat; import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; +import com.android.internal.inputmethod.DirectBootAwareness; import com.android.internal.inputmethod.IInputContentUriToken; import com.android.internal.inputmethod.IInputMethodPrivilegedOperations; import com.android.internal.inputmethod.ImeTracing; @@ -1869,8 +1870,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return true; } - @Override - public List getInputMethodList(@UserIdInt int userId) { + private List getInputMethodListInternal(@UserIdInt int userId, + @DirectBootAwareness int directBootAwareness) { if (UserHandle.getCallingUserId() != userId) { mContext.enforceCallingPermission( Manifest.permission.INTERACT_ACROSS_USERS_FULL, null); @@ -1883,13 +1884,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } final long ident = Binder.clearCallingIdentity(); try { - return getInputMethodListLocked(resolvedUserIds[0]); + return getInputMethodListLocked(resolvedUserIds[0], directBootAwareness); } finally { Binder.restoreCallingIdentity(ident); } } } + @Override + public List getInputMethodList(@UserIdInt int userId) { + return getInputMethodListInternal(userId, DirectBootAwareness.AUTO); + } + + @Override + public List getAwareLockedInputMethodList(@UserIdInt int userId, + @DirectBootAwareness int directBootAwareness) { + return getInputMethodListInternal(userId, directBootAwareness); + } + @Override public List getEnabledInputMethodList(@UserIdInt int userId) { if (UserHandle.getCallingUserId() != userId) { @@ -1912,9 +1924,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } @GuardedBy("mMethodMap") - private List getInputMethodListLocked(@UserIdInt int userId) { + private List getInputMethodListLocked(@UserIdInt int userId, + @DirectBootAwareness int directBootAwareness) { final ArrayList methodList; - if (userId == mSettings.getCurrentUserId()) { + if (userId == mSettings.getCurrentUserId() + && directBootAwareness == DirectBootAwareness.AUTO) { // Create a copy. methodList = new ArrayList<>(mMethodList); } else { @@ -1924,7 +1938,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new ArrayMap<>(); AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, methodMap, - methodList); + methodList, directBootAwareness); } return methodList; } @@ -4389,17 +4403,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static void queryInputMethodServicesInternal(Context context, @UserIdInt int userId, ArrayMap> additionalSubtypeMap, - ArrayMap methodMap, ArrayList methodList) { + ArrayMap methodMap, ArrayList methodList, + @DirectBootAwareness int directBootAwareness) { methodList.clear(); methodMap.clear(); - // Note: We do not specify PackageManager.MATCH_ENCRYPTION_* flags here because the default - // behavior of PackageManager is exactly what we want. It by default picks up appropriate - // services depending on the unlock state for the specified user. + final int directBootAwarenessFlags; + switch (directBootAwareness) { + case DirectBootAwareness.ANY: + directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; + break; + case DirectBootAwareness.AUTO: + directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AUTO; + break; + default: + directBootAwarenessFlags = PackageManager.MATCH_DIRECT_BOOT_AUTO; + Slog.e(TAG, "Unknown directBootAwareness=" + directBootAwareness + + ". Falling back to DirectBootAwareness.AUTO"); + break; + } + final int flags = PackageManager.GET_META_DATA + | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS + | directBootAwarenessFlags; final List services = context.getPackageManager().queryIntentServicesAsUser( - new Intent(InputMethod.SERVICE_INTERFACE), - PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, - userId); + new Intent(InputMethod.SERVICE_INTERFACE), flags, userId); methodList.ensureCapacity(services.size()); methodMap.ensureCapacity(services.size()); @@ -4448,7 +4476,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mMyPackageMonitor.clearKnownImePackageNamesLocked(); queryInputMethodServicesInternal(mContext, mSettings.getCurrentUserId(), - mAdditionalSubtypeMap, mMethodMap, mMethodList); + mAdditionalSubtypeMap, mMethodMap, mMethodList, DirectBootAwareness.AUTO); // Construct the set of possible IME packages for onPackageChanged() to avoid false // negatives when the package state remains to be the same but only the component state is @@ -4752,7 +4780,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private List getInputMethodListAsUser(@UserIdInt int userId) { synchronized (mMethodMap) { - return getInputMethodListLocked(userId); + return getInputMethodListLocked(userId, DirectBootAwareness.AUTO); } } @@ -4777,7 +4805,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new ArrayMap<>(); AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, - methodMap, methodList); + methodMap, methodList, DirectBootAwareness.AUTO); return methodMap; } @@ -5406,7 +5434,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter()); for (int userId : userIds) { final List methods = all - ? getInputMethodListLocked(userId) + ? getInputMethodListLocked(userId, DirectBootAwareness.AUTO) : getEnabledInputMethodListLocked(userId); if (userIds.length > 1) { pr.print("User #"); @@ -5641,7 +5669,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new ArrayMap<>(); AdditionalSubtypeUtils.load(additionalSubtypeMap, userId); queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap, - methodMap, methodList); + methodMap, methodList, DirectBootAwareness.AUTO); final InputMethodSettings settings = new InputMethodSettings( mContext.getResources(), mContext.getContentResolver(), methodMap, userId, false);