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);