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

Commit 68eed418 authored by Ben Murdoch's avatar Ben Murdoch
Browse files

Make ModifierShortcutManager multiuser aware.

Instead of using the cached system user context, we now keep
track of the current foreground user (maintained by PhoneWindowManager)
and use that user to resolve Roles and PackageManager queries. This
means that we will resolve the correct application launch intents for
the appropriate user.

This is especially important in HSUM builds, where the system user is
never the foreground user and so roles would never resolve correctly.

Flag: com.android.server.flags.modifier_shortcut_manager_multiuser
Bug: 351963350
Test: atest ModifierShortcutManagerTests ModifierShortcutTests

Change-Id: I98d70ebd1f067d27df52275bf82517fab1473ec8
parent 187ee73b
Loading
Loading
Loading
Loading
+133 −38
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.policy;

import static com.android.server.flags.Flags.modifierShortcutManagerMultiuser;

import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.role.RoleManager;
@@ -82,6 +84,10 @@ public class ModifierShortcutManager {
    private final SparseArray<String> mRoleShortcuts = new SparseArray<String>();
    private final SparseArray<String> mShiftRoleShortcuts = new SparseArray<String>();
    private final Map<String, Intent> mRoleIntents = new HashMap<String, Intent>();
    private final SparseArray<ComponentName> mComponentShortcuts = new SparseArray<>();
    private final SparseArray<ComponentName> mShiftComponentShortcuts = new SparseArray<>();
    private final Map<ComponentName, Intent> mComponentIntents =
            new HashMap<ComponentName, Intent>();

    private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();

@@ -115,23 +121,31 @@ public class ModifierShortcutManager {

    private final Context mContext;
    private final Handler mHandler;
    private final RoleManager mRoleManager;
    private final PackageManager mPackageManager;
    private boolean mSearchKeyShortcutPending = false;
    private boolean mConsumeSearchKeyUp = true;
    private UserHandle mCurrentUser;

    ModifierShortcutManager(Context context, Handler handler) {
    ModifierShortcutManager(Context context, Handler handler, UserHandle currentUser) {
        mContext = context;
        mHandler = handler;
        mPackageManager = mContext.getPackageManager();
        mRoleManager = mContext.getSystemService(RoleManager.class);
        mRoleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
        RoleManager rm = mContext.getSystemService(RoleManager.class);
        rm.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(),
                (String roleName, UserHandle user) -> {
                    mRoleIntents.remove(roleName);
                }, UserHandle.ALL);
        mCurrentUser = currentUser;
        loadShortcuts();
    }

    void setCurrentUser(UserHandle newUser) {
        mCurrentUser = newUser;

        // Role based shortcuts may resolve to different apps for different users
        // so clear the cache.
        mRoleIntents.clear();
        mComponentIntents.clear();
    }

    /**
     * Gets the shortcut intent for a given keycode+modifier. Make sure you
     * strip whatever modifier is used for invoking shortcuts (for example,
@@ -147,9 +161,11 @@ public class ModifierShortcutManager {
     * to invoke the shortcut.
     * @return The intent that matches the shortcut, or null if not found.
     */
    @Nullable
    private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
        // If a modifier key other than shift is also pressed, skip it.
        final boolean isShiftOn = KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_SHIFT_ON);
        final boolean isShiftOn = KeyEvent.metaStateHasModifiers(
                metaState, KeyEvent.META_SHIFT_ON);
        if (!isShiftOn && !KeyEvent.metaStateHasNoModifiers(metaState)) {
            return null;
        }
@@ -161,37 +177,54 @@ public class ModifierShortcutManager {

        // First try the exact keycode (with modifiers).
        int shortcutChar = kcm.get(keyCode, metaState);
        if (shortcutChar != 0) {
            shortcutIntent = shortcutMap.get(shortcutChar);
        if (shortcutChar == 0) {
            return null;
        }
        shortcutIntent = shortcutMap.get(shortcutChar);

        // Next try the primary character on that key.
        if (shortcutIntent == null) {
            // Next try the primary character on that key.
            shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
            if (shortcutChar != 0) {
            if (shortcutChar == 0) {
                return null;
            }
            shortcutIntent = shortcutMap.get(shortcutChar);
        }

        if (shortcutIntent == null) {
                    // Check for role based shortcut
            // Next check for role based shortcut with primary character.
            String role = isShiftOn ? mShiftRoleShortcuts.get(shortcutChar)
                    : mRoleShortcuts.get(shortcutChar);
            if (role != null) {
                shortcutIntent = getRoleLaunchIntent(role);
            }
        }

        if (modifierShortcutManagerMultiuser()) {
            if (shortcutIntent == null) {
                // Next check component based shortcuts with primary character.
                ComponentName component = isShiftOn
                        ? mShiftComponentShortcuts.get(shortcutChar)
                        : mComponentShortcuts.get(shortcutChar);
                if (component != null) {
                    shortcutIntent = resolveComponentNameIntent(component);
                }
            }
        }

        return shortcutIntent;
    }

    private Intent getRoleLaunchIntent(String role) {
        Intent intent = mRoleIntents.get(role);
        if (intent == null) {
            if (mRoleManager.isRoleAvailable(role)) {
                String rolePackage = mRoleManager.getDefaultApplication(role);
            Context context = modifierShortcutManagerMultiuser()
                    ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
            RoleManager rm = context.getSystemService(RoleManager.class);
            PackageManager pm = context.getPackageManager();
            if (rm.isRoleAvailable(role)) {
                String rolePackage = rm.getDefaultApplication(role);
                if (rolePackage != null) {
                    intent = mPackageManager.getLaunchIntentForPackage(rolePackage);
                    intent = pm.getLaunchIntentForPackage(rolePackage);
                    if (intent != null) {
                        intent.putExtra(EXTRA_ROLE, role);
                        mRoleIntents.put(role, intent);
@@ -249,7 +282,17 @@ public class ModifierShortcutManager {
                                + " className=" + className + " shortcutChar=" + shortcutChar);
                        continue;
                    }
                    if (modifierShortcutManagerMultiuser()) {
                        ComponentName componentName = new ComponentName(packageName, className);
                        if (isShiftShortcut) {
                            mShiftComponentShortcuts.put(shortcutChar, componentName);
                        } else {
                            mComponentShortcuts.put(shortcutChar, componentName);
                        }
                        continue;
                    } else {
                        intent = resolveComponentNameIntent(packageName, className);
                    }
                } else if (categoryName != null) {
                    if (roleName != null) {
                        Log.w(TAG, "Cannot specify role bookmark when category is present for"
@@ -287,20 +330,38 @@ public class ModifierShortcutManager {
        }
    }

    @Nullable
    private Intent resolveComponentNameIntent(ComponentName componentName) {
        Intent intent = mComponentIntents.get(componentName);
        if (intent == null) {
            intent = resolveComponentNameIntent(
                    componentName.getPackageName(), componentName.getClassName());
            if (intent != null) {
                mComponentIntents.put(componentName, intent);
            }
        }
        return intent;
    }

    @Nullable
    private Intent resolveComponentNameIntent(String packageName, String className) {
        int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                | PackageManager.MATCH_DIRECT_BOOT_AWARE
        Context context = modifierShortcutManagerMultiuser()
                ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
        PackageManager pm = context.getPackageManager();
        int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
        if (!modifierShortcutManagerMultiuser()) {
            flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE
                    | PackageManager.MATCH_UNINSTALLED_PACKAGES;
        }
        ComponentName componentName = new ComponentName(packageName, className);
        try {
            mPackageManager.getActivityInfo(componentName, flags);
            pm.getActivityInfo(componentName, flags);
        } catch (PackageManager.NameNotFoundException e) {
            String[] packages = mPackageManager.canonicalToCurrentPackageNames(
            String[] packages = pm.canonicalToCurrentPackageNames(
                    new String[] { packageName });
            componentName = new ComponentName(packages[0], className);
            try {
                mPackageManager.getActivityInfo(componentName, flags);
                pm.getActivityInfo(componentName, flags);
            } catch (PackageManager.NameNotFoundException e1) {
                Log.w(TAG, "Unable to add bookmark: " + packageName
                        + "/" + className + " not found.");
@@ -399,7 +460,11 @@ public class ModifierShortcutManager {
            if (intent != null) {
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                try {
                    if (modifierShortcutManagerMultiuser()) {
                        mContext.startActivityAsUser(intent, mCurrentUser);
                    } else {
                        mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                    }
                } catch (ActivityNotFoundException ex) {
                    Slog.w(TAG, "Dropping application launch key because "
                            + "the activity to which it is registered was not found: "
@@ -417,7 +482,11 @@ public class ModifierShortcutManager {
        if (shortcutIntent != null) {
            shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            try {
                if (modifierShortcutManagerMultiuser()) {
                    mContext.startActivityAsUser(shortcutIntent, mCurrentUser);
                } else {
                    mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
                }
            } catch (ActivityNotFoundException ex) {
                Slog.w(TAG, "Dropping shortcut key combination because "
                        + "the activity to which it is registered was not found: "
@@ -526,6 +595,30 @@ public class ModifierShortcutManager {
            }
        }

        if (modifierShortcutManagerMultiuser()) {
            for (int i = 0; i < mComponentShortcuts.size(); i++) {
                ComponentName component = mComponentShortcuts.valueAt(i);
                KeyboardShortcutInfo info = shortcutInfoFromIntent(
                        (char) (mComponentShortcuts.keyAt(i)),
                        resolveComponentNameIntent(component),
                        false);
                if (info != null) {
                    shortcuts.add(info);
                }
            }

            for (int i = 0; i < mShiftComponentShortcuts.size(); i++) {
                ComponentName component = mShiftComponentShortcuts.valueAt(i);
                KeyboardShortcutInfo info = shortcutInfoFromIntent(
                        (char) (mShiftComponentShortcuts.keyAt(i)),
                        resolveComponentNameIntent(component),
                        true);
                if (info != null) {
                    shortcuts.add(info);
                }
            }
        }

        return new KeyboardShortcutGroup(
                mContext.getString(R.string.keyboard_shortcut_group_applications),
                shortcuts);
@@ -548,23 +641,26 @@ public class ModifierShortcutManager {

        CharSequence label;
        Icon icon;
        Context context = modifierShortcutManagerMultiuser()
                ? mContext.createContextAsUser(mCurrentUser, 0) : mContext;
        PackageManager pm = context.getPackageManager();
        ActivityInfo resolvedActivity = intent.resolveActivityInfo(
                mPackageManager, PackageManager.MATCH_DEFAULT_ONLY);
                pm, PackageManager.MATCH_DEFAULT_ONLY);
        if (resolvedActivity == null) {
            return null;
        }
        boolean isResolver = com.android.internal.app.ResolverActivity.class.getName().equals(
                resolvedActivity.name);
        if (isResolver) {
            label = getIntentCategoryLabel(mContext,
            label = getIntentCategoryLabel(context,
                    intent.getSelector().getCategories().iterator().next());
            if (label == null) {
                return null;
            }
            icon = Icon.createWithResource(mContext, R.drawable.sym_def_app_icon);
            icon = Icon.createWithResource(context, R.drawable.sym_def_app_icon);

        } else {
            label = resolvedActivity.loadLabel(mPackageManager);
            label = resolvedActivity.loadLabel(pm);
            icon = Icon.createWithResource(
                    resolvedActivity.packageName, resolvedActivity.getIconResource());
        }
@@ -609,5 +705,4 @@ public class ModifierShortcutManager {
        }
        return context.getString(resid);
    };

}
+6 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
import static android.view.contentprotection.flags.Flags.createAccessibilityOverlayAppOpEnabled;

import static com.android.hardware.input.Flags.emojiAndScreenshotKeycodesAvailable;
import static com.android.server.flags.Flags.modifierShortcutManagerMultiuser;
import static com.android.server.flags.Flags.newBugreportKeyboardShortcut;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
@@ -2281,7 +2282,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
        mSettingsObserver = new SettingsObserver(mHandler);
        mSettingsObserver.observe();
        mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
        mModifierShortcutManager = new ModifierShortcutManager(
                mContext, mHandler, UserHandle.of(mCurrentUserId));
        mUiMode = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_defaultUiModeType);
        mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
@@ -6506,6 +6508,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        if (statusBar != null) {
            statusBar.setCurrentUser(newUserId);
        }
        if (modifierShortcutManagerMultiuser()) {
            mModifierShortcutManager.setCurrentUser(UserHandle.of(newUserId));
        }
    }

    @Override
+4 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
@@ -77,6 +78,7 @@ public class ModifierShortcutManagerTests {
        XmlResourceParser testBookmarks = mResources.getXml(
                com.android.frameworks.wmtests.R.xml.bookmarks);

        doReturn(mContext).when(mContext).createContextAsUser(anyObject(), anyInt());
        when(mContext.getResources()).thenReturn(mResources);
        when(mContext.getPackageManager()).thenReturn(mPackageManager);
        when(mResources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks);
@@ -98,7 +100,8 @@ public class ModifierShortcutManagerTests {
                .canonicalToCurrentPackageNames(aryEq(new String[] { "com.test2" }));


        mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
        mModifierShortcutManager = new ModifierShortcutManager(
                mContext, mHandler, UserHandle.SYSTEM);
    }

    @Test