Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 04a22633 authored by Wilson Wu's avatar Wilson Wu
Browse files

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
parent 6560e43b
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -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<InputMethodInfo> 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.
     *
+47 −0
Original line number Diff line number Diff line
/*
 * 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 <strong>both</strong>
     * {@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;
}
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ interface IInputMethodManager {

    // TODO: Use ParceledListSlice instead
    List<InputMethodInfo> getInputMethodList(int userId);
    List<InputMethodInfo> getAwareLockedInputMethodList(int userId, int directBootAwareness);
    // TODO: Use ParceledListSlice instead
    List<InputMethodInfo> getEnabledInputMethodList(int userId);
    List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
+3 −1
Original line number Diff line number Diff line
@@ -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<InputMethodInfo> getInputMethodList() {
+46 −18
Original line number Diff line number Diff line
@@ -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<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
    private List<InputMethodInfo> 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<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
        return getInputMethodListInternal(userId, DirectBootAwareness.AUTO);
    }

    @Override
    public List<InputMethodInfo> getAwareLockedInputMethodList(@UserIdInt int userId,
            @DirectBootAwareness int directBootAwareness) {
        return getInputMethodListInternal(userId, directBootAwareness);
    }

    @Override
    public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
        if (UserHandle.getCallingUserId() != userId) {
@@ -1912,9 +1924,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    }

    @GuardedBy("mMethodMap")
    private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId) {
    private List<InputMethodInfo> getInputMethodListLocked(@UserIdInt int userId,
            @DirectBootAwareness int directBootAwareness) {
        final ArrayList<InputMethodInfo> 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<String, List<InputMethodSubtype>> additionalSubtypeMap,
            ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList) {
            ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> 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<ResolveInfo> 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<InputMethodInfo> 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<InputMethodInfo> 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);